// 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;
}