// 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); }
LmRoutineCppObj::~LmRoutineCppObj() { // assert that caller has called dealloc before destroying this object LM_ASSERT(invocationInfo_ == NULL && interfaceObj_ == NULL && outputRow_ == NULL); }
// Deletes the LmResultSet object at a given index. void LmRoutineJava::cleanupLmResultSet(ComUInt32 index, ComDiagsArea *diagsArea) { LM_ASSERT(index < resultSetList_.entries()); ((LmResultSetJava *)resultSetList_[index])->close( diagsArea ); resultSetList_.removeAt(index); }
// This method creates a LmResultSetJava object for the // passed in java.sql.ResultSet object (newRS) and inserts // it into resultSetList_. // // Parameters: // newRS - A java.sql.ResultSet object // paramPos - The position (1-based) of newRS // in the Java method signature. // da - ComDiagsArea object to report any errors. // This object should not be NULL. LmResult LmRoutineJava::populateResultSetInfo(LmHandle newRS, Int32 paramPos, ComDiagsArea *da) { LmResult result = LM_OK; jobject newRSRef = (jobject)newRS; LM_ASSERT(da != NULL); // SPJ method can return same java.sql.ResultSet object in // multiple OUT params but we ignore such duplicates. // We also ignore a NULL java.sql.ResultSet object. if( newRSRef == NULL || isDuplicateRS( newRSRef )) return result; LmResultSetJava::LmResultSetInfoStatus rsInfoStatus; LmResultSetJava *newLmRS = new (collHeap()) LmResultSetJava( getLM(), (LmHandle)newRSRef, paramPos, getNameForDiags(), rsInfoStatus, connectionList_, da ); // If the constructor returned a success status then insert // the newLmRS object into resultSetList_ otherwise delete it. if( rsInfoStatus == LmResultSetJava::RS_INFO_OK ) { // Order the objects inserted in the resultSetList_ based on // the order in which the result set cursors were opened. ComUInt32 i; LmResultSetJava *lmRS; for( i = 0; i < resultSetList_.entries(); i++ ) { lmRS = (LmResultSetJava *)resultSetList_[i]; if( newLmRS->rsCounter_ < lmRS->rsCounter_ ) break; } resultSetList_.insertAt( i, newLmRS ); } else { delete newLmRS; newLmRS = NULL; // Ignore closed result sets if( rsInfoStatus == LmResultSetJava::RS_INFO_CLOSED ) result = LM_OK; else result = LM_ERR; } return result; }
LmResult LmLanguageManagerC::invokeRoutine( LmRoutine *handle, void *inputRow, void *outputRow, ComDiagsArea *diagsArea) { LmRoutine *routine = (LmRoutine *) handle; LM_ASSERT(routine); LmResult result = routine->invokeRoutine(inputRow, outputRow, diagsArea); return result; }
// Deletes the given LmResultSet object. // Any error during the close will be reported in the // diagsArea, if available. Asserts on an invalid pointer. void LmRoutineJava::cleanupLmResultSet(LmResultSet *resultSet, ComDiagsArea *diagsArea) { for (ComUInt32 index=0; index < resultSetList_.entries(); index++) { if (resultSetList_[index] == resultSet) { ((LmResultSetJava *)resultSetList_[index])->close(diagsArea); resultSetList_.removeAt(index); return; } } // passed in resultset param is not a valid LmResultSet pointer. LM_ASSERT(0); }
// This method checks if the passed in java.sql.ResultSet object // reference (newRS) is already part of a LmResultSetJava // object in the resultSetList_. // // The parameter newRS should not be NULL. // Returns TRUE if a match is found FALSE otherwise NABoolean LmRoutineJava::isDuplicateRS( LmHandle newRS ) { JNIEnv *jni = (JNIEnv*)getLM()->jniEnv_; LmResultSetJava *lmRS; jobject newRSRef = (jobject)newRS; ComUInt32 indx; LM_ASSERT(newRS != NULL); for (indx = 0; indx < resultSetList_.entries(); indx++) { lmRS = (LmResultSetJava *)resultSetList_[indx]; // IsSameObject() JNI call compares the object references // of it's parameters if (jni->IsSameObject( (jobject)lmRS->getResultSet(), newRSRef )) return TRUE; } // End for loop return FALSE; }
LmRoutineCSql::LmRoutineCSql(const char *sqlName, const char *externalName, const char *librarySqlName, ComUInt32 numSqlParam, char *routineSig, ComUInt32 maxResultSets, ComRoutineTransactionAttributes transactionAttrs, ComRoutineSQLAccess sqlAccessMode, ComRoutineExternalSecurity externalSecurity, Int32 routineOwnerId, const char *parentQid, ComUInt32 inputRowLen, ComUInt32 outputRowLen, const char *currentUserName, const char *sessionUserName, LmParameter *parameters, LmLanguageManagerC *lm, LmHandle routine, LmContainer *container, ComDiagsArea *diagsArea) : LmRoutineC(sqlName, externalName, librarySqlName, numSqlParam, routineSig, maxResultSets, COM_LANGUAGE_C, COM_STYLE_SQL, transactionAttrs, sqlAccessMode, externalSecurity, routineOwnerId, parentQid, inputRowLen, outputRowLen, currentUserName, sessionUserName, parameters, lm, routine, container, diagsArea), cBuf_(NULL), data_(NULL), ind_(numSqlParam * sizeof(short)) { ComUInt32 i = 0; data_ = (char **) collHeap()->allocateMemory(numSqlParam * sizeof(char *)); // Allocate C data buffers. Each LmCBuffer instance points to a C // buffer and the data_ buffer is an array of pointers to the C data // buffers. The LmCBuffer is mainly used to track the actual size of // the C buffers because each buffer has some extra bytes at the end // to protect against buffer overwrites. // // cBuf_ -> LmCBuffer LmCBuffer LmCBuffer ... // | | | // v v v // buffer buffer buffer ... // ^ ^ ^ // | | | // data_[0] data_[1] data_[2] ... // // NOTE: the cBuf_ array is allocated on the C++ heap because we // want to manage the collection as a single array, and we want // constructors and destructors to be called when the collection is // created and destroyed. Right now, NAMemory and NABasic object // interfaces do not provide the appropriate array versions of new // and delete operators to accomplish these things. cBuf_ = new LmCBuffer[numSqlParam_]; LM_ASSERT(cBuf_); for (i = 0; i < numSqlParam_; i++) { LmParameter &p = lmParams_[i]; LmCBuffer &cBuf = cBuf_[i]; ComUInt32 dataBytes = 0; switch (p.direction()) { // NOTE: The code currently supports IN and OUT parameters for C // routines. There is no reason we couldn't support INOUT as // well, which will be needed if we ever provide stored // procedures written in C. But the INOUT code paths have not // been implemented yet. case COM_INPUT_COLUMN: dataBytes = p.inSize(); break; case COM_OUTPUT_COLUMN: dataBytes = p.outSize(); break; default: LM_ASSERT(0); break; } switch (p.fsType()) { case COM_VCHAR_FSDT: case COM_VCHAR_DBL_FSDT: { // VARCHAR(N) CHARACTER SET ISO88591 // VARCHAR(N) CHARACTER SET UCS2 // This is a VARCHAR parameter. Allocate one buffer that will // hold the VC struct and the data. Data will begin at the first // 8-byte boundary following the VC struct. ComUInt32 vcBytes = ROUND8(sizeof(SQLUDR_VC_STRUCT)) + dataBytes; cBuf.init(vcBytes); data_[i] = cBuf.getBuffer(); // Initialize the VC struct SQLUDR_VC_STRUCT *vc = (SQLUDR_VC_STRUCT *) cBuf.getBuffer(); char *charPtr = (char *) vc; vc->data = charPtr + ROUND8(sizeof(SQLUDR_VC_STRUCT)); vc->length = dataBytes; } break; case COM_FCHAR_FSDT: case COM_FCHAR_DBL_FSDT: case COM_SIGNED_DECIMAL_FSDT: case COM_UNSIGNED_DECIMAL_FSDT: case COM_DATETIME_FSDT: case COM_SIGNED_NUM_BIG_FSDT: case COM_UNSIGNED_NUM_BIG_FSDT: { // CHAR(N) CHARACTER SET ISO88591 // CHAR(N) CHARACTER SET UCS2 // DECIMAL [UNSIGNED] // DATE, TIME, TIMESTAMP // NUMERIC precision > 18 // These types require a null-terminated C string. Add one to // dataBytes to account for the null terminator. cBuf.init(dataBytes + 1); data_[i] = cBuf.getBuffer(); } break; default: { // All other types cBuf.init(dataBytes); data_[i] = cBuf.getBuffer(); } break; } // switch (p.fsType()) } // for each param } // LmRoutineCSql::LmRoutineCSql
LmResult LmRoutineJava::invokeRoutine(void *inputRow, void *outputRow, ComDiagsArea *da) { // Delete the LmResultSet objects for re-invocations // This will also close the Java result set objects // and the Java connections that they are part of cleanupResultSets(da); // This will close any default connections that do not have // result sets associated with them closeDefConnWithNoRS(da); // Cleanup the list maintained in LmUtlity.cpp file that will get // populated with default connection objects that may get created // during this routine's invocation. lmUtilityInitConnList((JNIEnv*)getLM()->jniEnv_, (jmethodID)getLM()->connCloseId_); // Set the default catalog & schema as system properties. These // values are then retrieved by LmSQLMXDriver class for setting // it on a getConnection() call if (getDefaultCatSchFlag()) { // Determine the catalog & schema values that will be in effect for // this UDR. If the values are set globally(with catalog/schema // props in CQD) they are used else the catalog/schema of // the UDR are used. const char *catalog = (getLM()->sysCatalog_) ? getLM()->sysCatalog_ : udrCatalog_; const char *schema = (getLM()->sysSchema_) ? getLM()->sysSchema_ : udrSchema_; if (getLM()->setSystemProperty("sqlmx.udr.catalog", catalog, da) == LM_ERR) return LM_ERR; if (getLM()->setSystemProperty("sqlmx.udr.schema", schema, da) == LM_ERR) return LM_ERR; } const char *parentQid; if ((parentQid = getParentQid()) == NULL) parentQid = "NONE"; if (getLM()->setSystemProperty("sqlmx.udr.parentQid", parentQid, da) == LM_ERR) return LM_ERR; // Set SQL access mode in LmUtility. This will be checked while SPJ // is trying to make a JDBC connection. lmUtilitySetSqlAccessMode(getSqlAccessMode()); // Set Transaction Attribute in LmUtility. This will be checked while SPJ // is trying to join a transaction. lmUtilitySetTransactionAttrs(getTransactionAttrs()); LmResult result = LM_OK; // Set the Definer Authentication Token as system property for // Definer Rights SPJs. This value is then retrieved by LmSQLMXDriver class // for setting the password property in getConnection() call. if ( externalSecurity_ == COM_ROUTINE_EXTERNAL_SECURITY_DEFINER ) { char *defAuthToken = new (collHeap()) char[DR_SPJ_TOKEN_LEN + 1]; result = generateDefAuthToken(defAuthToken, da); if (result != LM_ERR) result = getLM()->setSystemProperty("sqlmx.udr.defAuthToken", defAuthToken, da); NADELETEBASIC(defAuthToken, collHeap()); if (result == LM_ERR) { char errStr[LMJ_ERR_SIZE_256]; sprintf (errStr, ": Error returned from setting System Property: %s.", "sqlmx.udr.defAuthToken"); *da << DgSqlCode(-LME_INTERNAL_ERROR) << DgString0(errStr); return LM_ERR; } } lm_->setRoutineIsActive(TRUE); switch (retType_) { case LmJavaType::JT_VOID: result = voidRoutine(outputRow, NULL); break; default: // Other return types are not supported. In the future if we // support routines with non-void return types we will need to // add case blocks to this switch statement. LM_ASSERT(0); break; } lm_->setRoutineIsActive(FALSE); // Reset the sqlmx.udr.defAuthToken system property for // Definer Rights SPJs. if ( externalSecurity_ == COM_ROUTINE_EXTERNAL_SECURITY_DEFINER ) { result = getLM()->clearSystemProperty("sqlmx.udr.defAuthToken", da); if (result == LM_ERR) { char errStr[LMJ_ERR_SIZE_256]; sprintf (errStr, ": Error returned from Resetting System Property: %s.", "sqlmx.udr.defAuthToken"); *da << DgSqlCode(-LME_INTERNAL_ERROR) << DgString0(errStr); return LM_ERR; } } // Get the list containing the default connection objects // from LmUtility.cpp and create a LmConnection object for // each item in that list. NAList<jobject> &connList = lmUtilityGetConnList(); while(connList.entries()) { jobject conn = connList[0]; LmConnection *lmConn = new (collHeap()) LmConnection(getLM(), conn, LmConnection::DEFAULT_CONN, getTransactionAttrs()); connectionList_.insert( lmConn ); connList.removeAt(0); } // reset SQL Access mode to COM_UNKNOWN_ROUTINE_SQL_ACCESS lmUtilitySetSqlAccessMode(COM_UNKNOWN_ROUTINE_SQL_ACCESS); // reset Transaction Attributes to COM_UNKNOWN_ROUTINE_TRANSACTION_ATTRIBUTE lmUtilitySetTransactionAttrs(COM_UNKNOWN_ROUTINE_TRANSACTION_ATTRIBUTE); return result; }