// returned error code described in w:/common/csconvert.h Int32 ComAnsiNameToUCS2 ( const char * inAnsiNameInMBCS // in - valid name in default ANSI name char set , NAWchar * outBuf4AnsiNameInUCS2 // out - out buffer , const Int32 outBufSizeInNAWchars // in - out buffer max len in NAWchars , const NABoolean padWithSpaces // in - default is FALSE ) { if (outBuf4AnsiNameInUCS2 == NULL || outBufSizeInNAWchars <= 0) return -2; // CNV_ERR_BUFFER_OVERRUN - No output buffer or not big enough if (inAnsiNameInMBCS == NULL) return -3; // CNV_ERR_NOINPUT - No input buffer or input cnt <= 0 else if (strlen(inAnsiNameInMBCS) == 0) { outBuf4AnsiNameInUCS2[0] = 0; return 0; // success } Int32 inAnsiNameLenInBytes = (Int32)strlen(inAnsiNameInMBCS); Int32 outBufSizeInBytes = outBufSizeInNAWchars * BYTES_PER_NAWCHAR; Int32 ansiNameCharSet = (Int32)ComGetNameInterfaceCharSet(); Int32 convAnsiNameCS = (Int32)/*cnv_charset*/convertCharsetEnum (ansiNameCharSet); char * pFirstByteOfTheUntranslatedChar = NULL; UInt32 iTranslatedStrLenInBytes = 0; UInt32 iNumberOfTranslatedChars = 0; Int32 iConvErrorCode = LocaleToUTF16 ( cnv_version1 // in - const enum cnv_version version , inAnsiNameInMBCS // in - const char * in_bufr , (Int32) inAnsiNameLenInBytes // in - const Int32 in_len_in_bytes , (const char *) outBuf4AnsiNameInUCS2 // out - const char * out_bufr , (Int32)(outBufSizeInBytes - BYTES_PER_NAWCHAR) // in - const Int32 out_bufr_max_len_in_bytes , (cnv_charset) convAnsiNameCS // in - enum cnv_charset conv_charset , pFirstByteOfTheUntranslatedChar // out - char * & first_untranslated_char , &iTranslatedStrLenInBytes // out - UInt32 * output_data_len_p , (Int32) 0 // in - const Int32 conv_flags , (Int32) FALSE // in - const Int32 addNullAtEnd_flag , &iNumberOfTranslatedChars // out - UInt32 * translated_char_cnt_p // , 0xffffffff // in - UInt32 max_chars_to_convert = 0xffffffff ); Int32 outStrLenInNAWchars = iTranslatedStrLenInBytes / BYTES_PER_NAWCHAR; outBuf4AnsiNameInUCS2[outStrLenInNAWchars] = 0; // Append the NULL terminator if (iConvErrorCode == 0 && padWithSpaces) { wc_str_pad ( (NAWchar *) &outBuf4AnsiNameInUCS2[outStrLenInNAWchars] // out - NAWchar *str , outBufSizeInNAWchars - outStrLenInNAWchars - 1 // in - Int32 length , unicode_char_set::SPACE // in - NAWchar padchar = unicode_char_set::SPACE ); outBuf4AnsiNameInUCS2[outBufSizeInNAWchars-1] = 0; // Append the NULL terminator } return iConvErrorCode; }
LmResult LmRoutineCSql::invokeRoutine(void *inputRow, void *outputRow, ComDiagsArea *da) { ComUInt32 argc = numSqlParam_; ComUInt32 i = 0; short *udrInd = (short *) ind_.getBuffer(); // Code handles UDF functions with upto 32 parameters. LM_ASSERT1(argc <= 32, "Parameters more than 32 are not allowed."); // We can return early if the caller is requesting a FINAL call but // not FINAL is necessary because the INITIAL call was never made if (callType_ == SQLUDR_CALLTYPE_FINAL && !finalCallRequired_) return LM_OK; ComUInt32 numIn = 0; ComUInt32 numOut = 0; // Build the argument vector if (callType_ != SQLUDR_CALLTYPE_FINAL) { for (i = 0; i < argc; i++) { LmParameter &p = lmParams_[i]; LM_ASSERT1(p.direction() != COM_INOUT_COLUMN, "INOUT parameters are not supported for C routines"); if (p.isIn()) { numIn++; // Set the input null indicator NABoolean nullVal = p.isNullInput((char *) inputRow); udrInd[i] = (nullVal ? SQLUDR_NULL : SQLUDR_NOTNULL); // Make a copy of the input value if (! nullVal) { char *inData = ((char *) inputRow) + p.inDataOffset(); char *inCopy = data_[i]; ComUInt32 inBytes = p.inSize(); switch (p.fsType()) { case COM_FCHAR_FSDT: { // CHAR(N) CHARACTER SET ISO88591 memcpy(inCopy, inData, inBytes); inCopy[inBytes] = 0; } break; case COM_FCHAR_DBL_FSDT: { // CHAR(N) CHARACTER SET UCS2 memcpy(inCopy, inData, inBytes); inCopy[inBytes] = 0; inCopy[inBytes + 1] = 0; } break; case COM_VCHAR_FSDT: case COM_VCHAR_DBL_FSDT: { // VARCHAR(N) CHARACTER SET ISO88591 // VARCHAR(N) CHARACTER SET UCS2 SQLUDR_VC_STRUCT *vc = (SQLUDR_VC_STRUCT *) inCopy; ComUInt32 inDataLen = p.actualInDataSize(inputRow); memcpy(&(vc->length), &inDataLen, 4); memcpy(vc->data, inData, inDataLen); } break; case COM_SIGNED_BIN16_FSDT: case COM_UNSIGNED_BIN16_FSDT: { // SMALLINT [UNSIGNED] // NUMERIC 0 <= precision <= 4 memcpy(inCopy, inData, 2); } break; case COM_SIGNED_BIN32_FSDT: case COM_UNSIGNED_BIN32_FSDT: case COM_FLOAT32_FSDT: { // INTEGER [UNSIGNED] // REAL // NUMERIC 5 <= precision <= 9 memcpy(inCopy, inData, 4); } break; case COM_SIGNED_BIN64_FSDT: case COM_FLOAT64_FSDT: { // LARGEINT // FLOAT // DOUBLE PRECISION // NUMERIC 10 <= precision <= 18 memcpy(inCopy, inData, 8); } break; 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: { // DECIMAL [UNSIGNED] // DATE, TIME, TIMESTAMP // NUMERIC precision > 18 memcpy(inCopy, inData, inBytes); inCopy[inBytes] = '\0'; } break; default: { char msg[256]; sprintf(msg, "Unknown parameter type: %d", p.fsType()); LM_ASSERT1(0, msg); } break; } // switch (p.fsType()) } // if not null } // if (isInput) else { numOut++; // Set the output null indicator udrInd[i] = SQLUDR_NOTNULL; // Initialize the output buffer char *outData = (char *)outputRow + p.outDataOffset(); char *outCopy = data_[i]; ComUInt32 outBytes = p.outSize(); switch (p.fsType()) { case COM_FCHAR_FSDT: { // CHAR(N) CHARACTER SET ISO88591 memset(outCopy, ' ', outBytes); outCopy[outBytes] = 0; } break; case COM_FCHAR_DBL_FSDT: { // CHAR(N) CHARACTER SET UCS2 NAWchar *wOutCopy = (NAWchar *) outCopy; ComUInt32 outChars = outBytes / sizeof(NAWchar); wc_str_pad(wOutCopy, outChars); // pads with space by default wOutCopy[outChars] = 0; } break; case COM_VCHAR_FSDT: case COM_VCHAR_DBL_FSDT: { // VARCHAR(N) CHARACTER SET ISO88591 // VARCHAR(N) CHARACTER SET UCS2 SQLUDR_VC_STRUCT *vc = (SQLUDR_VC_STRUCT *) outCopy; vc->length = outBytes; memset(vc->data, 0, outBytes); } break; case COM_SIGNED_BIN16_FSDT: case COM_UNSIGNED_BIN16_FSDT: { // SMALLINT [UNSIGNED] // NUMERIC 0 <= precision <= 4 memset(outCopy, 0, 2); } break; case COM_SIGNED_BIN32_FSDT: case COM_UNSIGNED_BIN32_FSDT: case COM_FLOAT32_FSDT: { // INTEGER [UNSIGNED] // REAL // NUMERIC 5 <= precision <= 9 memset(outCopy, 0, 4); } break; case COM_SIGNED_BIN64_FSDT: case COM_FLOAT64_FSDT: { // LARGEINT // FLOAT // DOUBLE PRECISION // NUMERIC 10 <= precision <= 18 memset(outCopy, 0, 8); } break; 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: { // DECIMAL [UNSIGNED] // DATE, TIME, TIMESTAMP // NUMERIC precision > 18 memset(outCopy, ' ', outBytes); outCopy[outBytes] = 0; } break; default: { char msg[256]; sprintf(msg, "Unknown parameter type value: %d", p.fsType()); LM_ASSERT1(0, msg); } break; } // switch (p.fsType()) } // if (isInput) else ... } // for each parameter } // if this is not a FINAL call else { // This is a FINAL call. Set all null indicators to SQLUDR_NULL // and zero out data buffers. for (i = 0; i < argc; i++) { udrInd[i] = SQLUDR_NULL; LmCBuffer &cBuf = cBuf_[i]; cBuf.set(0); } } // Initialize SQLSTATE to all '0' characters and add a null terminator str_pad(sqlState_, SQLUDR_SQLSTATE_SIZE - 1, '0'); sqlState_[SQLUDR_SQLSTATE_SIZE - 1] = 0; // Initialize SQL text to all zero bytes str_pad(msgText_, SQLUDR_MSGTEXT_SIZE, '\0'); // Now we can call the routine body... ComSInt32 rc = SQLUDR_INVOKE(routine_, argc, data_, udrInd, sqlState_, msgText_, callType_, stateArea_, udrInfo_); // Set the call type for the next invocation to NORMAL if this is // an INITIAL call if (callType_ == SQLUDR_CALLTYPE_INITIAL) { callType_ = SQLUDR_CALLTYPE_NORMAL; finalCallRequired_ = TRUE; } else if (callType_ == SQLUDR_CALLTYPE_FINAL) { // We are done if this is a FINAL call finalCallRequired_ = FALSE; return LM_OK; } LmResult lmResult = LM_OK; if (rc != SQLUDR_ERROR) { // Copy data and null indicator to caller's output buffers for (i = numIn; i < argc && lmResult == LM_OK; i++) { LmParameter &p = lmParams_[i]; NABoolean isOutput = (p.direction() == COM_OUTPUT_COLUMN ? TRUE : FALSE); if (isOutput) { // Look at the returned null indicator. Raise an error if the // routine returned an invalid null indicator. NABoolean isNull = TRUE; switch(udrInd[i]) { case SQLUDR_NOTNULL: isNull = FALSE; break; case SQLUDR_NULL: break; default: { *da << DgSqlCode(-LME_UDF_INVALID_DATA) << DgString0(getNameForDiags()) << DgInt0((Lng32) i + 1) << DgString1("Invalid null indicator"); lmResult = LM_ERR; } break; } // Write the null indicator into the output row if (lmResult == LM_OK) p.setNullOutput((char *) outputRow, isNull); // If value is not NULL, set data. if (lmResult == LM_OK && !isNull) { char *outData = ((char *)outputRow) + p.outDataOffset(); char *outCopy = data_[i]; ComUInt32 outBytes = p.outSize(); switch (p.fsType()) { case COM_FCHAR_FSDT: case COM_FCHAR_DBL_FSDT: { // CHAR(N) CHARACTER SET ISO88591 // CHAR(N) CHARACTER SET UCS2 p.setOutChar(outputRow, outCopy, outBytes); } break; case COM_VCHAR_FSDT: case COM_VCHAR_DBL_FSDT: { // VARCHAR(N) CHARACTER SET ISO88591 // VARCHAR(N) CHARACTER SET UCS2 SQLUDR_VC_STRUCT *vc = (SQLUDR_VC_STRUCT *) outCopy; if (vc->length > outBytes) { char msg[100]; sprintf(msg, "VARCHAR length should not exceed %d", outBytes); *da << DgSqlCode(-LME_UDF_INVALID_DATA) << DgString0(getNameForDiags()) << DgInt0((Lng32) i + 1) << DgString1(msg); lmResult = LM_ERR; } else { p.setOutChar(outputRow, vc->data, vc->length); } } break; case COM_SIGNED_BIN16_FSDT: case COM_UNSIGNED_BIN16_FSDT: { // SMALLINT [UNSIGNED] // NUMERIC 0 <= precision <= 4 memcpy(outData, outCopy, 2); } break; case COM_SIGNED_BIN32_FSDT: case COM_UNSIGNED_BIN32_FSDT: case COM_FLOAT32_FSDT: { // INTEGER [UNSIGNED] // REAL // NUMERIC 5 <= precision <= 9 memcpy(outData, outCopy, 4); } break; case COM_SIGNED_BIN64_FSDT: case COM_FLOAT64_FSDT: { // LARGEINT // FLOAT // DOUBLE PRECISION // NUMERIC 10 <= precision <= 18 memcpy(outData, outCopy, 8); } break; 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: { // DECIMAL [UNSIGNED] // DATE, TIME, TIMESTAMP // NUMERIC precision > 18 p.setOutChar(outputRow, outCopy, outBytes); } break; default: { char msg[256]; sprintf(msg, "Unknown parameter type value: %d", p.fsType()); LM_ASSERT1(0, msg); } break; } // switch (p.fsType()) } // if (lmResult == LM_OK && !isNull) } // if (isOutput) } // for each LmParameter } // if (rc != SQLUDR_ERROR) if (lmResult == LM_OK && rc != SQLUDR_SUCCESS) { sqlState_[SQLUDR_SQLSTATE_SIZE - 1] = 0; lmResult = processReturnStatus(rc, da); } return lmResult; } // LmRoutineCSql::invokeRoutine
// Copy the return string without null terminator into outAddr_. LmResult LmParameter::setOutChar(void *dataPtr, const char *src, ComUInt32 lengthInBytes) { LmResult result = LM_OK; #ifdef LANGMAN if (lengthInBytes > outSize_) { lengthInBytes = outSize_; result = LM_PARAM_OVERFLOW; } str_cpy_all((char*)dataPtr + outDataOffset(), src, (Lng32)lengthInBytes); // Copy length into varchar length indicator switch (outVCLenIndSize()) { case 0: break; case 2: { ComUInt16 tempLen = (ComUInt16) lengthInBytes; memcpy((char*)dataPtr + outVCLenIndOffset(), &tempLen, sizeof(short)); break; } case 4: memcpy((char*)dataPtr + outVCLenIndOffset(), &lengthInBytes, sizeof(Int32)); break; default: LM_ASSERT1(0, "Unknown varchar indicator length."); break; } // Blank-pad FIXED char types. if (DFS2REC::isSQLFixedChar(fsType())) { if (outSize_ > lengthInBytes) { switch (encodingCharSet_) { case CharInfo::ISO88591 : case CharInfo::SJIS : case CharInfo::UTF8 : str_pad((char*)dataPtr + outDataOffset_ + lengthInBytes, (Lng32)(outSize_ - lengthInBytes), ' '); break; case CharInfo::UNICODE : wc_str_pad((NAWchar*)((char*)dataPtr + outDataOffset_ + lengthInBytes), (Lng32)(outSize_ - lengthInBytes)/2, unicode_char_set::space_char()); break; default : char msg[256]; sprintf(msg, "Unknown Character set value: %d", encodingCharSet_); LM_ASSERT1(0, msg); break; } } } #endif return result; }