blob: e4db61cca39697bea52197ffaa8243f145403398 [file] [log] [blame]
/**********************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
**********************************************************************/
/* -*-C++-*-
******************************************************************************
*
* File: LmUtility.cpp
* Description: Native C code used by LmUtility.java
*
* Created: 06/06/2002
* Language: C++
*
*
******************************************************************************
*/
#include "LmUtility.h"
#include "ComCextdecs.h"
#include "NAString.h"
#include "Int64.h"
#include "str.h"
#include <stdlib.h>
#include "LmDebug.h"
#include "sqlcli.h"
#include "LmAssert.h"
#include <sys/types.h>
#include <unistd.h>
#define GETPID getpid
#include "dtm/tm.h"
// sqlAccessMode stores the SQL Access mode the SPJ was registered with.
// This value is populated before SPJ method is called and is used
// by LmSQLMXDriver class to decide whether to allow SPJ to get a datbase
// connection or not. This is only used for Type 4 connections.
// Type 2 connections work as they used to.
Int32 sqlAccessMode =0;
void lmUtilitySetSqlAccessMode(Int32 mode) { sqlAccessMode = mode; }
// sqlAccessMode stores the SQL Access mode the SPJ was registered with.
// This value is populated before SPJ method is called and is used
// by LmSQLMXDriver class to decide whether to allow SPJ to get a datbase
// connection or not. This is only used for Type 4 connections.
// Type 2 connections work as they used to.
// transactionAttrs stores the Transaction Required the SPJ was registered with.
// This value is populated before SPJ method is called and is used
// by LmSQLMXDriver class to decide whether to allow SPJ to join a datbase
// transaction or not.
Int32 transactionAttrs =0;
void lmUtilitySetTransactionAttrs(Int32 transAttrs) { transactionAttrs = transAttrs; }
// 'lmUtilityConnList' below contains a list of java.sql.Connection
// object references of default connections i.e.
// Java connection objects created using the url
// "jdbc:default:connection".
//
// These connection objects come from the LmSQLMXDriver java
// class via the 'addConnection()' native method. Whenever a
// default connection is created within a SPJ method the
// LmSQLMXDriver class will call the above native method passing
// it the new created default connection's object reference.
//
// The basic idea behind having this list is to provide a
// mechanism for the LmRoutine class to retrieve all the
// default connection objects that may get created as part
// of the SPJ invocation. The following steps should be followed:
//
// 1. Just before a SPJ method gets invoked the 'lmUtilityInitConnList()'
// should be called to empty 'lmUtilityConnList'. If there are any
// connection objects present in the list then they are closed and
// their global reference are deleted.
//
// 2. Invoke the SPJ method. Now the 'lmUtilityConnList' will get populated
// with default connection objects that the SPJ method may have created.
//
// 3. Immediately after the SPJ method invocation completes
// call the 'lmUtilityGetConnList()' method to get the
// 'lmUtilityConnList'.
// 4. Retrieve all the connection entries from 'lmUtilityConnList' and
// then remove them from the above list.
//
// Note:
// The caller of 'lmUtilityGetConnList()' will be responsible to delete
// the retrieved connection references when they are no longer needed.
//
NAList<jobject> lmUtilityConnList(NULL);
// If there are any Java connection objects present in
// 'lmUtilityConnList' then the following actions are taken:
// - Calls the 'close()' method on the connection
// - Deletes the object reference
// - Removes the connection entry from 'lmUtilityConnList'
//
// The method expects the following as input:
// - Pointer to the JNIEnv interface
// - JNI method ID of java.sql.Connection.close() method
//
void lmUtilityInitConnList( JNIEnv *jni, jmethodID connCloseId )
{
while( lmUtilityConnList.entries() )
{
jobject conn = lmUtilityConnList[0];
if( conn )
{
jni->CallVoidMethod( conn,
connCloseId );
jni->ExceptionClear();
}
jni->DeleteGlobalRef( conn );
lmUtilityConnList.removeAt(0);
}
lmUtilityConnList.clear();
}
// Returns the 'connList' as a reference
NAList<jobject> &lmUtilityGetConnList() { return lmUtilityConnList; }
// LCOV_EXCL_START
static void Throw(JNIEnv *env, const char *msg)
{
jclass c = env->FindClass("java/lang/Exception");
//
// If c is NULL an exception has already been thrown
//
if (c != NULL)
{
env->ThrowNew(c, msg);
}
env->DeleteLocalRef(c);
}
void SQL_ERROR_HANDLER(Lng32 sqlCode)
{
// This is a no-op for now. Might be useful in the future for logic
// that needs to be executed after any CLI error.
}
// LCOV_EXCL_STOP
// The MXStatement class provides a simple interface into the SQL/MX
// CLI and can be used for SQL operations in a C++ program that is not
// a preprocessed embedded program. The LmUtility::utils() native
// method supports an "ExecSql" operation where an arbitrary SQL
// string is compiled and executed through the MXStatement interface.
class MXStatement
{
public:
// This class creates input and output descriptors with a fixed
// maximum on the number of columns. Removing this limitation is
// future work.
enum Constants
{
MAX_COLUMNS_IN_DESC = 500
};
MXStatement()
{
initialized_ = false;
moduleId_.module_name = NULL;
stmtId_.version = SQLCLI_CURRENT_VERSION;
stmtId_.name_mode = stmt_handle;
stmtId_.module = &moduleId_;
stmtId_.identifier = 0;
stmtId_.handle = 0;
stmtTextDesc_.version = SQLCLI_CURRENT_VERSION;
stmtTextDesc_.name_mode = desc_handle;
stmtTextDesc_.module = &moduleId_;
stmtTextDesc_.identifier = 0;
stmtTextDesc_.handle = 0;
inDesc_.version = SQLCLI_CURRENT_VERSION;
inDesc_.name_mode = desc_handle;
inDesc_.module = &moduleId_;
inDesc_.identifier = 0;
inDesc_.handle = 0;
outDesc_.version = SQLCLI_CURRENT_VERSION;
outDesc_.name_mode = desc_handle;
outDesc_.module = &moduleId_;
outDesc_.identifier = 0;
outDesc_.handle = 0;
numInColumns_ = 0;
numOutColumns_ = 0;
}
// LCOV_EXCL_START
Lng32 init(const char *&status)
{
Lng32 result = 0;
status = "OK";
if (initialized_)
return result;
stmtText_ = NULL;
if (result == 0)
{
result = SQL_EXEC_ClearDiagnostics(NULL);
if (result != 0)
{
status = "SQL_EXEC_ClearDiagnostics failed";
}
}
if (result == 0)
{
result = SQL_EXEC_AllocStmt(&stmtId_, 0);
if (result != 0)
{
status = "SQL_EXEC_AllocStmt failed";
}
}
if (result == 0)
{
result = SQL_EXEC_AllocDesc(&stmtTextDesc_, 1);
if (result != 0)
{
status = "SQL_EXEC_AllocDesc failed for statement text";
SQL_EXEC_DeallocStmt(&stmtId_);
}
}
if (result == 0)
{
result = SQL_EXEC_AllocDesc(&inDesc_, MAX_COLUMNS_IN_DESC);
SQL_ERROR_HANDLER(result);
if (result != 0)
{
status = "SQL_EXEC_AllocDesc failed for input descriptor";
SQL_EXEC_DeallocDesc(&stmtTextDesc_);
SQL_EXEC_DeallocStmt(&stmtId_);
}
}
if (result == 0)
{
result = SQL_EXEC_AllocDesc(&outDesc_, MAX_COLUMNS_IN_DESC);
SQL_ERROR_HANDLER(result);
if (result != 0)
{
status = "SQL_EXEC_AllocDesc failed for output descriptor";
SQL_EXEC_DeallocDesc(&inDesc_);
SQL_EXEC_DeallocDesc(&stmtTextDesc_);
SQL_EXEC_DeallocStmt(&stmtId_);
}
}
if (result == 0)
initialized_ = true;
SQL_ERROR_HANDLER(result);
return result;
}
// LCOV_EXCL_STOP
~MXStatement()
{
if (initialized_)
{
SQL_EXEC_ClearDiagnostics(NULL);
SQL_EXEC_DeallocDesc(&outDesc_);
SQL_EXEC_DeallocDesc(&inDesc_);
SQL_EXEC_DeallocDesc(&stmtTextDesc_);
SQL_EXEC_DeallocStmt(&stmtId_);
}
delete [] stmtText_;
}
// LCOV_EXCL_START
Lng32 prepare(const char *stmtText)
{
if (!initialized_)
{
return -9999;
}
delete [] stmtText_;
stmtText_ = new char[strlen(stmtText) + 1];
strcpy(stmtText_, stmtText);
Lng32 result = 0;
if (!result)
result = SQL_EXEC_ClearDiagnostics(NULL);
if (!result)
result = SQL_EXEC_SetDescItem(&stmtTextDesc_, 1, SQLDESC_TYPE,
SQLTYPECODE_CHAR, 0);
if (!result)
result = SQL_EXEC_SetDescItem(&stmtTextDesc_, 1, SQLDESC_LENGTH,
strlen(stmtText_), 0);
if (!result)
result = SQL_EXEC_SetDescItem(&stmtTextDesc_, 1, SQLDESC_VAR_PTR,
(Long) stmtText_, 0);
if (!result)
result = SQL_EXEC_Prepare(&stmtId_, &stmtTextDesc_);
if (!result)
result = SQL_EXEC_DescribeStmt(&stmtId_, &inDesc_, &outDesc_);
if (!result)
result = SQL_EXEC_GetDescEntryCountBasic(&outDesc_, &numOutColumns_);
if (!result)
result = SQL_EXEC_GetDescEntryCountBasic(&inDesc_, &numInColumns_);
SQL_ERROR_HANDLER(result);
return result;
}
Lng32 execute()
{
if (!initialized_)
{
return -9999;
}
Lng32 result = 0;
if (!result)
result = SQL_EXEC_ClearDiagnostics(NULL);
if (!result)
result = SQL_EXEC_ExecClose(&stmtId_, NULL, 0);
SQL_ERROR_HANDLER(result);
return result;
}
Lng32 executeUsingLong(Lng32 i)
{
if (!initialized_)
{
return -9999;
}
Lng32 result = 0;
if (!result)
result = SQL_EXEC_ClearDiagnostics(NULL);
if (!result)
result = SQL_EXEC_SetDescItem(&inDesc_, 1, SQLDESC_TYPE,
SQLTYPECODE_INTEGER, 0);
if (!result)
result = SQL_EXEC_SetDescItem(&inDesc_, 1, SQLDESC_LENGTH,
sizeof(i), 0);
if (!result)
result = SQL_EXEC_SetDescItem(&inDesc_, 1, SQLDESC_VAR_PTR,
(Long) &i, 0);
if (!result)
result = SQL_EXEC_ExecClose(&stmtId_, &inDesc_, 0);
SQL_ERROR_HANDLER(result);
return result;
}
Lng32 executeUsingString(const char *s, Lng32 len)
{
if (!initialized_)
{
return -9999;
}
Lng32 result = 0;
if (!result)
result = SQL_EXEC_ClearDiagnostics(NULL);
if (!result)
result = SQL_EXEC_SetDescItem(&inDesc_, 1, SQLDESC_TYPE,
(Lng32) SQLTYPECODE_CHAR, 0);
if (!result)
result = SQL_EXEC_SetDescItem(&inDesc_, 1, SQLDESC_LENGTH,
(Lng32) len, 0);
if (!result)
result = SQL_EXEC_SetDescItem(&inDesc_, 1, SQLDESC_VAR_PTR,
(Long) s, 0);
if (!result)
result = SQL_EXEC_ExecClose(&stmtId_, &inDesc_, 0);
SQL_ERROR_HANDLER(result);
return result;
}
Lng32 fetchEOD()
{
if (!initialized_)
{
return -9999;
}
Lng32 result = SQL_EXEC_Fetch(&stmtId_, NULL, 0);
if (result == 100)
{
result = 0;
}
SQL_ERROR_HANDLER(result);
return result;
}
Lng32 fetchLong(Lng32 &i)
{
if (!initialized_)
{
return -9999;
}
Lng32 result = 0;
if (!result)
result = SQL_EXEC_SetDescItem(&outDesc_, 1, SQLDESC_TYPE,
SQLTYPECODE_INTEGER, 0);
if (!result)
result = SQL_EXEC_SetDescItem(&outDesc_, 1, SQLDESC_LENGTH,
sizeof(i), 0);
if (!result)
result = SQL_EXEC_SetDescItem(&outDesc_, 1, SQLDESC_VAR_PTR,
(Long) &i, 0);
if (!result)
result = SQL_EXEC_Fetch(&stmtId_, &outDesc_, 0);
SQL_ERROR_HANDLER(result);
return result;
}
Lng32 fetchString(char *buf, Lng32 bufLen)
{
if (!initialized_)
{
return -9999;
}
Lng32 result = 0;
if (!result)
result = SQL_EXEC_SetDescItem(&outDesc_, 1, SQLDESC_TYPE,
SQLTYPECODE_VARCHAR, 0);
if (!result)
result = SQL_EXEC_SetDescItem(&outDesc_, 1, SQLDESC_LENGTH,
bufLen, 0);
if (!result)
result = SQL_EXEC_SetDescItem(&outDesc_, 1, SQLDESC_VAR_PTR,
(Long) buf, 0);
if (!result)
result = SQL_EXEC_Fetch(&stmtId_, &outDesc_, 0);
SQL_ERROR_HANDLER(result);
return result;
}
Lng32 fetchStrings(char **strings, Lng32 bufLen)
{
if (!initialized_)
return -9999;
Lng32 result = 0;
for (Lng32 i = 0; i < numOutColumns_ && !result; i++)
{
if (!result)
result = SQL_EXEC_SetDescItem(&outDesc_, i + 1, SQLDESC_TYPE,
SQLTYPECODE_VARCHAR, 0);
if (!result)
result = SQL_EXEC_SetDescItem(&outDesc_, i + 1, SQLDESC_LENGTH,
bufLen, 0);
if (!result)
result = SQL_EXEC_SetDescItem(&outDesc_, i + 1, SQLDESC_VAR_PTR,
(Long) (strings[i]), 0);
}
if (!result)
result = SQL_EXEC_Fetch(&stmtId_, &outDesc_, 0);
SQL_ERROR_HANDLER(result);
return result;
}
Lng32 close()
{
if (!initialized_)
{
return -9999;
}
Lng32 result = 0;
if (!result)
result = SQL_EXEC_CloseStmt(&stmtId_);
SQL_ERROR_HANDLER(result);
return result;
}
Lng32 getNumInColumns() { return numInColumns_; }
Lng32 getNumOutColumns() { return numOutColumns_; }
// LCOV_EXCL_STOP
protected:
SQLSTMT_ID stmtId_;
SQLMODULE_ID moduleId_;
SQLDESC_ID stmtTextDesc_;
SQLDESC_ID inDesc_;
SQLDESC_ID outDesc_;
Lng32 numInColumns_;
Lng32 numOutColumns_;
char *stmtText_;
bool initialized_;
}; // class MXStatement
//
// This is the LmUtility.nativeUtils method. It takes one string as
// input and produces one string as output. The output string gets
// written to the first element of the String[] array object passed in
// as the jobjectArray parameter.
//
// Although we do not document this method for customers, there is
// nothing preventing customer code from calling this method. So don't
// put anything in the method that you wouldn't want customers
// doing. Currently this function just serves as an entry point to
// various systems calls such as TMF operations and getting/setting
// environment variables. There is nothing here that customers could
// not do on their own if they wanted to.
//
JNIEXPORT void JNICALL Java_org_trafodion_sql_udr_LmUtility_nativeUtils
(JNIEnv * env, jclass jc, jstring js, jobjectArray joa)
{
const char *input = env->GetStringUTFChars(js, NULL);
if (input == NULL)
{
// OutOfMemory error already thrown
return;
}
NAString action(input);
TrimNAStringSpace(action);
short error;
NAString result("OK");
static MXStatement staticStmt;
// LCOV_EXCL_START
if (action.compareTo("GetTxName", NAString::ignoreCase) == 0)
{
Int64 transid;
error = GETTRANSID((short *) &transid);
if (error)
{
if (error == 75)
{
result = "No active transaction";
}
else
{
result = "GETTRANSID returned ";
result += LongToNAString((Lng32) error);
}
Throw(env, result.data());
}
else
{
short actualLen;
char text[256];
error = TRANSIDTOTEXT(transid, text, 255, &actualLen);
if (error)
{
result = "TRANSIDTOTEXT returned ";
result += LongToNAString((Lng32) error);
Throw(env, result);
}
else
{
text[actualLen] = 0;
result = text;
}
}
} // GetTxName
else if (action.compareTo("BeginTx", NAString::ignoreCase) == 0)
{
Int32 tag;
error = BEGINTRANSACTION(&tag);
if (error)
{
result = "BEGINTRANSACTION returned ";
result += LongToNAString((Lng32) error);
Throw(env, result);
}
} // BeginTx
else if (action.compareTo("CommitTx", NAString::ignoreCase) == 0)
{
error = ENDTRANSACTION();
if (error)
{
if (error == 75)
{
result = "No active transaction";
}
else
{
result = "ENDTRANSACTION returned ";
result += LongToNAString((Lng32) error);
}
Throw(env, result);
}
} // CommitTx
else if (action.compareTo("RollbackTx", NAString::ignoreCase) == 0)
{
error = ABORTTRANSACTION();
if (error)
{
if (error == 75)
{
result = "No active transaction";
}
else
{
result = "ABORTTRANSACTION returned ";
result += LongToNAString((Lng32) error);
}
Throw(env, result);
}
} // RollbackTx
else if (action.compareTo("GetProcessId", NAString::ignoreCase) == 0)
{
Lng32 pid = GETPID();
result = LongToNAString(pid);
} // GetProcessId
else if (action.index("GetEnv ", 0, NAString::ignoreCase) == 0)
{
NAString name = action;
name.remove(0, str_len("GetEnv "));
TrimNAStringSpace(name);
char *value = getenv(name.data());
if (value != NULL)
{
result = value;
}
else
{
result = "";
}
} // GetEnv
else if (action.index("PutEnv ", 0, NAString::ignoreCase) == 0)
{
NAString nameAndValue = action;
nameAndValue.remove(0, str_len("PutEnv "));
TrimNAStringSpace(nameAndValue);
Int32 retcode = putenv((char *) nameAndValue.data());
if (retcode != 0)
{
result = "putenv returned ";
result += LongToNAString((Lng32) retcode);
Throw(env, result);
}
} // PutEnv
else if (action.index("LmDebug ", 0, NAString::ignoreCase) == 0)
{
NAString name = action;
name.remove(0, str_len("LmDebug "));
LM_DEBUG0(name.data());
} // LmDebug
else if (action.index("ExecSql ", 0, NAString::ignoreCase) == 0)
{
NAString stmtText = action.remove(0, str_len("ExecSql "));
MXStatement s;
const char *status = "OK";
Lng32 retcode = 0;
retcode = s.init(status);
if (retcode == 0)
{
retcode = s.prepare(stmtText.data());
if (retcode != 0)
{
status = "PREPARE failed";
}
}
if (retcode == 0)
{
retcode = s.execute();
if (retcode != 0)
{
status = "EXECUTE failed";
}
}
if (retcode == 0)
{
retcode = s.fetchEOD();
if (retcode != 0)
{
status = "FETCH failed";
}
}
if (retcode == 0)
{
retcode = s.close();
if (retcode != 0)
{
status = "CLOSE failed";
}
}
if (retcode != 0)
{
char msg[256];
sprintf(msg, "[UdrSqlException %d] %s", retcode, status);
Throw(env, msg);
}
} // ExecSql
else if (action.index("FetchSql ", 0, NAString::ignoreCase) == 0)
{
// The incoming string is SQL statement text. The code below will
// prepare and execute the statement then fetch only the first
// row. It will build one long multi-line string containing all
// column values, one on each line. The multi-line string can be
// split by the Java caller into an array of Strings with the
// split("\n") method.
Lng32 i;
NAString stmtText = action.remove(0, str_len("FetchSql "));
MXStatement s;
const char *status = "OK";
Lng32 retcode = 0;
retcode = s.init(status);
if (!retcode)
{
retcode = s.prepare(stmtText.data());
if (retcode)
status = "PREPARE failed";
}
if (!retcode)
{
retcode = s.execute();
if (retcode)
status = "EXECUTE failed";
}
Lng32 numOutColumns = s.getNumOutColumns();
NABoolean stringsAllocated = FALSE;
char **argv = NULL;
if (!retcode && numOutColumns > 0)
{
argv = new char *[numOutColumns];
Lng32 bufLen = 1000;
for (i = 0; i < numOutColumns; i++)
argv[i] = new char[bufLen + 1];
stringsAllocated = TRUE;
retcode = s.fetchStrings(argv, bufLen);
if (retcode)
status = "FETCH STRINGS failed";
if (!retcode)
{
result = argv[0];
for (i = 1; i < numOutColumns; i++)
{
result += "\n";
result += argv[i];
}
}
}
if (!retcode)
{
retcode = s.fetchEOD();
if (retcode)
status = "FETCH EOD failed";
}
if (!retcode)
{
retcode = s.close();
if (retcode)
status = "CLOSE failed";
}
if (stringsAllocated)
{
for (i = 0; i < numOutColumns; i++)
delete [] argv[i];
delete [] argv;
}
if (retcode)
{
char msg[256];
sprintf(msg, "[UdrSqlException %d] %s", retcode, status);
Throw(env, msg);
}
} // FetchSql
else if (action.index("Prepare ", 0, NAString::ignoreCase) == 0)
{
NAString stmtText = action.remove(0, str_len("Prepare "));
const char *status = "OK";
Lng32 retcode = 0;
retcode = staticStmt.init(status);
if (retcode == 0)
{
retcode = staticStmt.prepare(stmtText.data());
if (retcode != 0)
{
status = "PREPARE failed";
}
}
if (retcode)
{
char msg[256];
sprintf(msg, "[UdrSqlException %d] %s", retcode, status);
Throw(env, msg);
}
} // Prepare
else if (action.index("ExecUsingString ", 0, NAString::ignoreCase) == 0)
{
NAString data = action.remove(0, str_len("ExecUsingString "));
const char *status = "OK";
Lng32 retcode = 0;
if (retcode == 0)
{
retcode = staticStmt.executeUsingString(data.data(),
(Lng32) data.length());
if (retcode != 0)
{
status = "EXECUTE failed";
}
}
if (retcode == 0)
{
retcode = staticStmt.fetchEOD();
if (retcode != 0)
{
status = "FETCH failed";
}
}
if (retcode == 0)
{
retcode = staticStmt.close();
if (retcode != 0)
{
status = "CLOSE failed";
}
}
if (retcode != 0)
{
char msg[256];
sprintf(msg, "[UdrSqlException %d] %s", retcode, status);
Throw(env, msg);
}
} // ExecUsingString
else if (action.index("FetchUsingString ", 0, NAString::ignoreCase) == 0)
{
NAString data = action.remove(0, str_len("FetchUsingString "));
const char *status = "OK";
Lng32 retcode = 0;
Int32 i = 0;
if (!retcode)
{
retcode = staticStmt.executeUsingString(data.data(),
(Lng32) data.length());
if (retcode)
status = "EXECUTE failed";
}
Lng32 numOutColumns = staticStmt.getNumOutColumns();
NABoolean stringsAllocated = FALSE;
char **argv = NULL;
if (!retcode && numOutColumns > 0)
{
argv = new char *[numOutColumns];
Lng32 bufLen = 1000;
for (i = 0; i < numOutColumns; i++)
argv[i] = new char[bufLen + 1];
stringsAllocated = TRUE;
retcode = staticStmt.fetchStrings(argv, bufLen);
if (retcode)
status = "FETCH STRINGS failed";
if (!retcode)
{
result = argv[0];
for (i = 1; i < numOutColumns; i++)
{
result += "\n";
result += argv[i];
}
}
}
if (!retcode)
{
retcode = staticStmt.fetchEOD();
if (retcode)
status = "FETCH EOD failed";
}
if (!retcode)
{
retcode = staticStmt.close();
if (retcode)
status = "CLOSE failed";
}
if (stringsAllocated)
{
for (i = 0; i < numOutColumns; i++)
delete [] argv[i];
delete [] argv;
}
if (retcode)
{
char msg[256];
sprintf(msg, "[UdrSqlException %d] %s", retcode, status);
Throw(env, msg);
}
} // FetchUsingString
else
{
//
// Over time other operations can be supported
//
result = "Invalid action: ";
result += action;
Throw(env, result);
}
// LCOV_EXCL_STOP
//
// Create the Java output string
//
if (env->ExceptionCheck() == JNI_FALSE)
{
jobject j = env->NewStringUTF(result.data());
env->SetObjectArrayElement(joa, 0, j);
}
}
// Calls the RegisterNatives() JNI method to register
// the native methods defined in this file to the
// appropriate LM Java class.
// RegisterNatives() removes the need for creating a
// DLL for the native methods on Yosemite systems.
//
// Input parameters:
// env : Pointer to JNI environment
// lmCls : Pointer to LmUtility class object
//
// Return Value:
// 0 : The native methods were registered successfully
// <0 : An exception was throw by the JVM. The caller
// is responsible to report any exceptions.
//
Int32 registerLmUtilityMethods(JNIEnv *env, jclass lmCls)
{
// To add new native methods to the 'jnm' array just
// increment the array size and set the new entry's fields
// as needed.
const Int32 numMethods = 2;
JNINativeMethod jnm[numMethods];
jnm[0].name = (char *)"nativeUtils";
jnm[0].signature = (char *)"(Ljava/lang/String;[Ljava/lang/String;)V";
jnm[0].fnPtr = (void *)Java_org_trafodion_sql_udr_LmUtility_nativeUtils;
jnm[1].name = (char *)"getTransactionId";
jnm[1].signature = (char *)"()[S";
jnm[1].fnPtr = (void *)Java_org_trafodion_sql_udr_LmUtility_getTransactionId;
// RegisterNatives() returns zero on success or a negative
// value on a failure.
return env->RegisterNatives(lmCls, &jnm[0], numMethods);
}
Int32 registerLmT2DriverMethods(JNIEnv *env, jclass lmCls)
{
// To add new native methods to the 'jnm' array just
// increment the array size and set the new entry's fields
// as needed.
const Int32 numMethods = 4;
JNINativeMethod jnm[numMethods];
jnm[0].name = (char *)"addConnection";
jnm[0].signature = (char *)"(Ljava/lang/Object;)V";
jnm[0].fnPtr = (void *)Java_com_tandem_sqlmx_LmT2Driver_addConnection;
jnm[1].name = (char *)"getSqlAccessMode";
jnm[1].signature = (char *)"()I";
jnm[1].fnPtr = (void *)Java_com_tandem_sqlmx_LmT2Driver_getSqlAccessMode;
jnm[2].name = (char *)"getTransId";
jnm[2].signature = (char *)"()J";
jnm[2].fnPtr = (void *)Java_com_tandem_sqlmx_LmT2Driver_getTransId;
jnm[3].name = (char *)"getTransactionAttrs";
jnm[3].signature = (char *)"()I";
jnm[3].fnPtr = (void *)Java_com_tandem_sqlmx_LmT2Driver_getTransactionAttrs;
// RegisterNatives() returns zero on success or a negative
// value on a failure.
return env->RegisterNatives(lmCls, &jnm[0], numMethods);
}
// This native method is called by LmT2Driver to get the SQL Access
// mode of the SPJ
JNIEXPORT jint JNICALL Java_com_tandem_sqlmx_LmT2Driver_getSqlAccessMode
(JNIEnv *env, jclass jc)
{
return (jint) sqlAccessMode;
}
// This native method is called by LmT2Driver to get the Transaction
// Attributes of the SPJ
JNIEXPORT jint JNICALL Java_com_tandem_sqlmx_LmT2Driver_getTransactionAttrs
(JNIEnv *env, jclass jc)
{
return (jint) transactionAttrs;
}
// This native method is called by the LmT2Driver Java class
// whenever a java.sql.Connection object of type default connection
// is created. The default connection's object reference is passed
// as input to this method.
//
// This method creates a global reference of the provided connection
// object and adds it to 'lmUtilityConnList'.
//
JNIEXPORT void JNICALL Java_com_tandem_sqlmx_LmT2Driver_addConnection
(JNIEnv * env, jclass jc, jobject conn)
{
LM_ASSERT( conn != NULL );
jobject newConn = env->NewGlobalRef( conn );
lmUtilityConnList.insert(newConn);
}
// This method returns the transaction id that can be passed
// down to Type 4 JDBC driver
JNIEXPORT jshortArray JNICALL Java_org_trafodion_sql_udr_LmUtility_getTransactionId
(JNIEnv * env, jclass jc)
{
// On Seaquest, SQL/NDCS/TSE all use 64-bit transactionid
Int64 transid;
short *stransid = (short *)&transid;
short error = GETTRANSID(stransid);
jshortArray returnArray = env->NewShortArray(4);
env->SetShortArrayRegion(returnArray, 0, 4, stransid);
return returnArray;
}
// This method is used by LmSQLMXDriver to retrieve the transaction id
// to be passed to MXOSRVR via JDBC T4 driver joinUDRTransaction method
JNIEXPORT jlong JNICALL Java_com_tandem_sqlmx_LmT2Driver_getTransId
(JNIEnv * env, jclass jc)
{
Int64 transId = 0;
short *stransId = (short *)&transId;
short error = GETTRANSID(stransId);
if (error)
transId = -1;
return (jlong) transId;
}