/*!
  @file           DBMSrvKnl_Session.cpp
  @author         Bernd Vorsprach - bernd.vorsprach@sap.com
  @brief          DBMServer to Kernel Communication - Implementation

\if EMIT_LICENCE

    ========== licence begin  GPL
    Copyright (c) 2003-2005 SAP AG

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end



\endif
*/

/*
  -----------------------------------------------------------------------------
  includes
  -----------------------------------------------------------------------------
 */
#include "SAPDB/DBM/Srv/KernelAccess/DBMSrvKnl_Session.hpp"
#include "SAPDB/ToolsCommon/Tools_DynamicUTF8String.hpp"

#include "heo02.h"
#include "heo03.h"
#include "hsp02.h"

#include "SAPDB/PacketInterface/PIn_Packet.h"
#include "SAPDB/PacketInterface/PIn_SpecialParts.h"

#define CMD_CONNECT_P1  "CONNECT \""
#define CMD_CONNECT_P2  "\" IDENTIFIED by :PW TIMEOUT 0"
#define CMD_RELEASE     "COMMIT WORK RELEASE"

/*-----------------------------------------------------------------------------*/
/*! @brief constructor */
DBMSrvKnl_Session :: DBMSrvKnl_Session
    ( )
{
  this->Reset();
} // end DBMSrvKnl_Session :: DBMSrvKnl_Session

/*-----------------------------------------------------------------------------*/
/*! @brief destructor */
DBMSrvKnl_Session :: ~DBMSrvKnl_Session
    ( )
{
  Release();
} // end DBMSrvKnl_Session :: ~DBMSrvKnl_Session

/*-----------------------------------------------------------------------------*/
/*! @brief public member */
bool DBMSrvKnl_Session :: NormalConnect
    ( const char * szDB,
      const char * szUserIn,
      const char * szPassword )
{
  this->oMessageList.ClearMessageList();

  // check user and password
  if ((szUserIn == NULL) || (szPassword == NULL) || (strlen(szUserIn) == 0) || (strlen(szPassword) == 0)) {
    SAPDBErr_MessageList oDBM(DBMSrv_DBMError(PARAM), 0);
    SAPDBErr_MessageList oMsg(DBMSRV_ERR_MISSDBUSRPWD);
    oDBM.AppendNewMessage(oMsg);
    this->oMessageList = oMsg;
    return false;
  } // end if

  if (this->Connect(DBMSrvKnl_Session::taskNormal, szDB )) {
    if(!this->ConnectUser(szUserIn, szPassword)) {
      this->Release();
    } else {
      this->bConnected = true;
    } // end if
  } // end if

  return this->oMessageList.IsEmpty();
} // end DBMSrvKnl_Session :: NormalConnect

/*-----------------------------------------------------------------------------*/
/*! @brief public member */
bool DBMSrvKnl_Session :: FallbackConnect
    ( const char * szDB,
      const char * szUserIn,
      const char * szPassword )
{
  this->oMessageList.ClearMessageList();

  // check user and password
  if ((szUserIn == NULL) || (szPassword == NULL) || (strlen(szUserIn) == 0) || (strlen(szPassword) == 0)) {
    SAPDBErr_MessageList oDBM(DBMSrv_DBMError(PARAM), 0);
    SAPDBErr_MessageList oMsg(DBMSRV_ERR_MISSDBUSRPWD);
    oDBM.AppendNewMessage(oMsg);
    this->oMessageList = oMsg;
    return false;
  } // end if

  if (this->Connect(DBMSrvKnl_Session::taskFallback, szDB )) {
    if(!this->ConnectUser(szUserIn, szPassword)) {
      this->Release();
    } else {
      this->bConnected = true;
    } // end if
  } // end if

  return this->oMessageList.IsEmpty();
} // end DBMSrvKnl_Session :: FallbackConnect

/*-----------------------------------------------------------------------------*/
/*! @brief public member */
bool DBMSrvKnl_Session :: EventConnect
    ( const char * szDB )
{
  this->oMessageList.ClearMessageList();

  if (this->Connect(DBMSrvKnl_Session::taskEvent, szDB )) {
    this->bConnected = true;
  } // end if

  return this->oMessageList.IsEmpty();
} // end DBMSrvKnl_Session :: EventConnect

/*-----------------------------------------------------------------------------*/
/*! @brief public member */
bool DBMSrvKnl_Session :: Release
    ( )
{
  bool bReturn = true;
  SAPDBErr_MessageList oLocalMsg;

  if (this->IsConnected()) {
    // send release command
    // create request packet
    PIn_RequestPacket  oPacket(this->pPacket, this->nPacketSize, this->nUnicode);
    // initialise request packet
    oPacket.InitVersion(csp_comp_db_manager, NULL);
    // create segement
    PIn_RequestSegment oSegment = oPacket.AddSegment(sp1m_dbs, sp1sm_session_sqlmode);
    oSegment.SetProducer(sp1pr_internal_cmd);
    // create command part
    PIn_Part oCommandPart = oSegment.AddPart(sp1pk_command);
    // fill command part
    oCommandPart.AddArgument();
    if (this->nUnicode) {
      oCommandPart.AddDataUTF8ToUCS2(CMD_RELEASE, (int) strlen(CMD_RELEASE));
    } else {
      oCommandPart.AddData(CMD_RELEASE, (int) strlen(CMD_RELEASE));
    } // end if
    // close part
    oSegment.ClosePart(oCommandPart);
    // close segment
    oPacket.CloseSegment(oSegment);
    // send request to kernel
    if (!Request(oPacket.Length())) {
      if (bReturn) oLocalMsg = this->LastMessage();
      bReturn = false;
    } // end if
    // receive answer from kernel and create answer packet
    PIn_ReplyPacket  oReplyPacket(Receive());
    // check answer packet
    if (!oReplyPacket.IsValid()) {
      if (bReturn) oLocalMsg = this->LastMessage();
      bReturn = false;
    } // end if

    sqlarelease (this->nSessionHandle);

    if (!oLocalMsg.IsEmpty()) this->oMessageList = oLocalMsg;
  } // end if

  this->Reset();
  return bReturn;
} // end DBMSrvKnl_Session :: Release

/*-----------------------------------------------------------------------------*/
/*! @brief public member */
bool DBMSrvKnl_Session :: Request
  ( const char * szCmd )
{ 
  // create request packet
  PIn_RequestPacket  oPacket(this->pPacket, this->nPacketSize, this->nUnicode);
  // initialise request packet
  oPacket.InitVersion(csp_comp_db_manager, NULL);
  // create segement
  PIn_RequestSegment oSegment = oPacket.AddSegment(sp1m_dbs, sp1sm_session_sqlmode);
  oSegment.SetProducer(sp1pr_internal_cmd);

  oSegment.GetRawHeader()->sp1c_with_info          () = true;
  oSegment.GetRawHeader()->sp1c_commit_immediately () = this->bAutoCommit;

  // create command part
  PIn_Part oCommandPart = oSegment.AddPart(sp1pk_command);
  // fill command part
  oCommandPart.AddArgument();

  Tools_DynamicUTF8String sCommand = szCmd;

  if (this->nUnicode) {
    oCommandPart.AddDataUTF8ToUCS2(szCmd, (int) strlen(szCmd));
  } else {
    oCommandPart.AddData(szCmd, (int) strlen(szCmd));
  } // end if

  // close part
  oSegment.ClosePart(oCommandPart);
  // close segment
  oPacket.CloseSegment(oSegment);

  // send request to kernel
  if (!Request(oPacket.Length())) {
    return false;
  } // end if

  return true;
} // end DBMSrvKnl_Session :: Request

/*-----------------------------------------------------------------------------*/
/*! @brief public member */
bool DBMSrvKnl_Session ::  Receive
  ( ResultType & oResultType )
{ 
  oResultType = DBMSrvKnl_Session::resultUnknown;

  // receive answer from kernel and create answer packet
  PIn_ReplyPacket  oPacket(Receive());
  // check answer packet
  if (!oPacket.IsValid()) {
    return false;
  } // end if

  // read data 
  PIn_ReplySegment oSegment     = oPacket.GetFirstSegment ();

  if (oSegment.ErrorCode() == 0) {

    // decide on answer the next steps
    if (oSegment.GetRawHeader()->sp1s_no_of_parts() != 0) {
      PIn_Part oData        = oSegment.FindPart(sp1pk_data);
      PIn_Part oShortInfo   = oSegment.FindPart(sp1pk_shortinfo);
      PIn_Part oResultCount = oSegment.FindPart(sp1pk_resultcount);
      PIn_Part oResultTable = oSegment.FindPart(sp1pk_resulttablename);
      PIn_Part oMsgList     = oSegment.FindPart(sp1pk_message_list);

      if (oShortInfo.IsValid() && oResultCount.IsValid() && oResultTable.IsValid()) {
        bool bEnd;
        if (!this->FetchRecord(bEnd, true)) {
          return false;
        } // end if
        oResultType = DBMSrvKnl_Session::resultSQL;
      } else if (oShortInfo.IsValid() && oData.IsValid()) {
        oResultType = DBMSrvKnl_Session::resultUtility;
      } else if (oMsgList.IsValid()) {
        oResultType = DBMSrvKnl_Session::resultMessage;
      } else if (oResultCount.IsValid()) {
        // result count only (answer for insert or update)
        oResultType = DBMSrvKnl_Session::resultNothing;
      } // end if

    } else {
      oResultType = DBMSrvKnl_Session::resultNothing;
    } // end if
  
  } else {
    this->ReadErrorText(oSegment);
    oResultType = DBMSrvKnl_Session::resultError;
    return false;
  } // end if

  return true;
} // end DBMSrvKnl_Session :: Receive

/*-----------------------------------------------------------------------------*/
/*! @brief public member */
bool DBMSrvKnl_Session :: Execute
  ( const char * szCmd )
{ 
  this->oMessageList.ClearMessageList();

  ResultType  oResultType;
  return this->Execute(szCmd, oResultType);
} // end DBMSrvKnl_Session :: Execute

/*-----------------------------------------------------------------------------*/
/*! @brief public member */
bool DBMSrvKnl_Session :: ExecuteWithoutCommit
  ( const char      * szCmd )
{
  this->oMessageList.ClearMessageList();

  bool bResult = false;
  bool bCommit = this->bAutoCommit;
  this->bAutoCommit  = false;
  ResultType  oResultType;
  bResult = Execute(szCmd, oResultType );
  this->bAutoCommit = bCommit;
  return bResult;
} // end DBMSrvKnl_Session :: ExecuteWithoutCommit

/*-----------------------------------------------------------------------------*/
/*! @brief public member */
bool DBMSrvKnl_Session :: Execute
  ( const char * szCmd,
    ResultType & oResultType )
{ 
  this->oMessageList.ClearMessageList();

  if (Request(szCmd)) {
    return Receive(oResultType);
  } // end if
  return false;
} // end DBMSrvKnl_Session :: Execute

/*-----------------------------------------------------------------------------*/
/*! @brief public member */
const SAPDBErr_MessageList DBMSrvKnl_Session :: KernelMessage
  ( )
{
  SAPDBErr_MessageList oKernelMsg;

  oKernelMsg.ClearMessageList();

  PIn_ReplyPacket  oPacket(this->pReceivePacket);
  // check answer packet
  if (oPacket.IsValid()) {
    PIn_ReplySegment oSegment = oPacket.GetFirstSegment ();
    if (oSegment.ErrorCode() == 0) {
      PIn_Part oPart   = oSegment.FindPart(sp1pk_message_list);
      if (oPart.IsValid()) {
        PIn_MessageListPart oMsgListPart(oPart);
        oKernelMsg = oMsgListPart.MessageList();
      } // end if
    } // end if
  } // end if

  return oKernelMsg;
} // end DBMSrvKnl_Session :: KernelMessage

/*-----------------------------------------------------------------------------*/
/*! @brief private member */
bool DBMSrvKnl_Session :: Connect
    ( DBMSrvKnl_Session::TaskType   oTaskTypeIn,
      const char                     * szDB )
{
  this->oMessageList.ClearMessageList();

  // check user and password
  if ((szDB == NULL) || (strlen(szDB) == 0)) {
    SAPDBErr_MessageList oDBM(DBMSrv_DBMError(PARAM), 0);
    SAPDBErr_MessageList oMsg(DBMSRV_ERR_MISSDBUSRPWD);
    oDBM.AppendNewMessage(oMsg);
    this->oMessageList = oMsg;
    return false;
  } // end if

  tsp01_Service       nService;
  tsp00_TaskId        nTaskId;
  tsp00_ErrText       pasErrtext;
  tsp01_CommErr       nCommRc;

  // fill argument nTaskId for sqlaconnect
  sqluid (&nTaskId);

  // fill argument nService for sqlaconnect
  switch (oTaskTypeIn) {
    case DBMSrvKnl_Session::taskNormal:
      nService.becomes(srvUser_esp01);
      break;
    case DBMSrvKnl_Session::taskFallback:
      nService.becomes(srvUtility_esp01);
      break;
    case DBMSrvKnl_Session::taskEvent:
      nService.becomes(srvEvent_esp01);
      break;
    default:
      {
        SAPDBErr_MessageList oMsg(DBMSRV_ERR_UNKNOWNTASK);
        this->oMessageList = oMsg;
        return false;
      }
      break;
  } // end switch

  // connect to kernel
  tsp00_NodeId tspNode;
  tsp00_DbName tspDB;

  sqlaconnect( nTaskId, 
               tspNode.rawAssign(""), 
               tspDB.rawAssign(szDB), 
               nService, 
               1, 
               &this->nSessionHandle,
               &this->nPacketSize, 
               (void **) &this->pPacket, 
               pasErrtext, 
               &nCommRc );

  if (nCommRc != commErrOk_esp01) {
    tsp00_ErrTextc       szErrtext;

    szErrtext.p2c(pasErrtext);

    SAPDBErr_MessageList oMsg(DBMSrv_DBMError(RTE), 0);
    SAPDBErr_MessageList oRTE(DBMSrv_ExtendedError(nCommRc), szErrtext.asCharp(), 0);
    oMsg.AppendNewMessage(oRTE);
    this->oMessageList = oMsg;
    return false;
  } // end if

  return true;
} // end DBMSrvKnl_Session :: Connect

/*-----------------------------------------------------------------------------*/
/*! @brief private member */
bool DBMSrvKnl_Session :: ConnectUser
    ( const char * szUsr,
      const char * szPassword )
{
  this->oMessageList.ClearMessageList();

  { 
    size_t i = 0;
    size_t j = 0;
    bool bUpper = true;

    // username
    bUpper = true;
    j = 0;
    for (i = 0; i <= strlen(szUsr); ++i) {
      if (((szUsr[i] == '"') || (szUsr[i] == '\'')) && ((i == 0) || (i == (strlen(szUsr)-1)))) {
        bUpper = false;
      } else {
        if (bUpper) {
          this->szUser[i] = toupper (szUsr[i]);
        } else {
          this->szUser[i] = szUsr[i];
        } // end if
      } // end if
    } // end for

    // password
    bUpper = true;
    j = 0;
    for (i = 0; i <= strlen(szPassword); ++i) {
      if (((szPassword[i] == '"') || (szPassword[i] == '\'')) && ((i == 0) || (i == (strlen(szPassword)-1)))) {
        bUpper = false;
      } else {
        if (bUpper) {
          this->szPwd[j] = toupper (szPassword[i]);
        } else {
          this->szPwd[j] = szPassword[i];
        } // end if
        ++j;
      } // end if
    } // end for
  } // end block

  {
    // create request packet
    PIn_RequestPacket  oPacket(this->pPacket, this->nPacketSize, this->nUnicode);
    // initialise request packet
    oPacket.InitVersion(csp_comp_db_manager, NULL);
    // create segement
    PIn_RequestSegment oSegment = oPacket.AddSegment(sp1m_dbs, sp1sm_session_sqlmode);

    oSegment.SetProducer(sp1pr_internal_cmd);

    // create command part
    PIn_Part oCommandPart = oSegment.AddPart(sp1pk_command);
    // fill commadn part
    oCommandPart.AddArgument(CMD_CONNECT_P1, (int) strlen(CMD_CONNECT_P1));
    oCommandPart.AddData    (this->szUser,   (int) strlen(this->szUser));
    oCommandPart.AddData    (CMD_CONNECT_P2, (int) strlen(CMD_CONNECT_P2));
    // close command part
    oSegment.ClosePart(oCommandPart);
    // create data part for crypted password
    PIn_Part oDataPart = oSegment.AddPart(sp1pk_data);

    // fill data part with crypted password
    tsp00_Byte    cByte = csp_defined_byte;
    tsp00_CryptPw cryptPwd;
    tsp00_Name    pasPwd;
    tsp00_TermId  oTermid;

    pasPwd.c2p(this->szPwd);
    s02applencrypt (pasPwd, cryptPwd);

    sqltermid (oTermid);

    oDataPart.AddArgument(&cByte,   sizeof(cByte));
    oDataPart.AddData    (cryptPwd, sizeof(cryptPwd));
    oDataPart.AddData    (&cByte,   sizeof(cByte));
    oDataPart.AddData    (oTermid,  sizeof(oTermid));

    // close part
    oSegment.ClosePart(oDataPart);
    // close segment
    oPacket.CloseSegment(oSegment);

    // send request to kernel
    if (!Request(oPacket.Length())) {
      return false;
    } // end if
  } // end block

  {
    // receive answer from kernel and create answer packet
    PIn_ReplyPacket  oPacket(Receive());
    // check answer packet
    if (!oPacket.IsValid()) {
      return false;
    } // end if

    // read data 
    PIn_ReplySegment oSegment     = oPacket.GetFirstSegment ();

    if (oSegment.ErrorCode() == 0) {

      PIn_Part         oPart = oSegment.FindPart(sp1pk_session_info_returned);

      if (oPart.IsValid()) {
        PIn_SessionInfoPart oSessionInfoPart(oPart);
        this->nUnicode = oSessionInfoPart.IsUnicode();
        this->bAutoCommit = true;
      } // end if
    
    } else {
      this->ReadErrorText(oSegment);
      return false;
    } // end if

  } // end block


  return true;
} // DBMSrvKnl_Session :: ConnectUser

/*-----------------------------------------------------------------------------*/
/*! @brief private member */
bool DBMSrvKnl_Session :: FetchRecord
    ( bool & bEnd,
      bool   bFirst )
{
  Tools_DynamicUTF8String sCommand;
  tsp00_Int4              nParams = this->ParamCount();
  tsp00_Int4              i = 0;

  bEnd = false;

  sCommand = bFirst ? "FETCH FIRST INTO ?" : "FETCH NEXT INTO ?";

  for (i = 1; i < nParams; ++i) {
    sCommand.Append(", ?");
  } // end for

  if (!this->Execute(sCommand.CharPtr())) {
    PIn_ReplyPacket  oPacket(this->pReceivePacket);
    // check answer packet
    if (oPacket.IsValid()) {
      PIn_ReplySegment oSegment = oPacket.GetFirstSegment ();
      if ((oSegment.ErrorCode() == 100) && !bFirst) {
        this->oMessageList.ClearMessageList();
        bEnd = true;
        return true;
      } // end if
    } // end if
    return false;
  } // end if

  return true;
} // end DBMSrvKnl_Session :: FetchRecord

/*-----------------------------------------------------------------------------*/
/*! @brief private member */
bool DBMSrvKnl_Session :: Request
    ( SAPDB_Int4 nRequestLength )
{
  tsp00_ErrText  pasErrtext;
  tsp01_CommErr  nCommRc;

  sqlarequest(this->nSessionHandle, 
              this->pPacket, 
              nRequestLength,
              pasErrtext,
              &nCommRc);

  if (nCommRc != commErrOk_esp01) {
    tsp00_ErrTextc       szErrtext;

    szErrtext.p2c(pasErrtext);

    SAPDBErr_MessageList oMsg(DBMSrv_DBMError(RTE), 0);
    SAPDBErr_MessageList oRTE(DBMSrv_ExtendedError(nCommRc), szErrtext.asCharp(), 0);
    oMsg.AppendNewMessage(oRTE);
    this->oMessageList = oMsg;
    return false;
  } // end if

  return true;
} // end DBMSrvKnl_Session :: Request

/*-----------------------------------------------------------------------------*/
/*! @brief public member */
tsp00_Int4 DBMSrvKnl_Session :: ParamCount
  ( )
{
  PIn_ReplyPacket  oPacket(this->pReceivePacket);
  // check answer packet
  if (oPacket.IsValid()) {
    PIn_ReplySegment oSegment = oPacket.GetFirstSegment ();
    if (oSegment.ErrorCode() == 0) {
      PIn_Part oShortInfo   = oSegment.FindPart(sp1pk_shortinfo);
      if (oShortInfo.IsValid()) {
        return oShortInfo.GetRawPart()->sp1p_arg_count();
      } // end if
    } // end if
  } // end if

  return 0;
} // end DBMSrvKnl_Session :: ParamCount

/*-----------------------------------------------------------------------------*/
/*! @brief public member */
tsp1_param_info * DBMSrvKnl_Session :: ParamInfo
  ( )
{
  PIn_ReplyPacket  oPacket(this->pReceivePacket);
  // check answer packet
  if (oPacket.IsValid()) {
    PIn_ReplySegment oSegment = oPacket.GetFirstSegment ();
    if (oSegment.ErrorCode() == 0) {
      PIn_Part oShortInfo = oSegment.FindPart(sp1pk_shortinfo);
      if (oShortInfo.IsValid()) {
        return  (tsp1_param_info *) oShortInfo.GetReadData();
      } // end if
    } // end if
  } // end if

  return NULL;
} // DBMSrvKnl_Session :: ParamInfo

/*-----------------------------------------------------------------------------*/
/*! @brief public member */
Tools_DynamicUTF8String DBMSrvKnl_Session :: FieldName 
  ( const tsp00_Int4     nField )
{
  Tools_DynamicUTF8String sField;

  PIn_ReplyPacket  oPacket(this->pReceivePacket);
  
  // check answer packet
  if (oPacket.IsValid()) {
    PIn_ReplySegment oSegment = oPacket.GetFirstSegment ();
    if (oSegment.ErrorCode() == 0) {
      PIn_Part oColumnNames = oSegment.FindPart(sp1pk_columnnames);
      int                     nParamCount = this->ParamCount();

      if (oColumnNames.IsValid()) {
        const tsp00_Byte * pNames      = oColumnNames.GetReadData();
        int                i           = 0;
        int                nLen        = 0;

        // get columns
        for (i = 1; i <= nParamCount; i++) {
          nLen = *pNames++;
          if (i == nField) {
            if (this->nUnicode) {
              sField.ConvertFromUCS2_Unaligned_Swap((Tools_DynamicUTF8String::UCS2Char *) pNames, (Tools_DynamicUTF8String::UCS2Char *) (pNames + nLen));
            } else {
              sField.ConvertFromASCII_Latin1((Tools_DynamicUTF8String::ASCIIConstPointer) pNames, (Tools_DynamicUTF8String::ASCIIConstPointer) (pNames + nLen));
            } // end if
            break;
          } // end if
          pNames += nLen;
        } // end for 

      } else {
        int i = 0;
        Tools_DynamicUTF8String sNumber;
        for (i = 1; i <= nParamCount; i++) {
          sNumber.ConvertFromInt(i);
          sField.Assign("Field").Append(sNumber);
        } // end for 
      }  // end if
    } // end if
  } // end if

  return sField;
} // end DBMSrvKnl_Session :: FieldName

/*-----------------------------------------------------------------------------*/
/*! @brief public member */
bool DBMSrvKnl_Session :: GetValue
    ( const tsp00_Int4     nField,
      DBMSrv_SQLField    & oField )
{
  PIn_ReplyPacket  oPacket(this->pReceivePacket);
  // check answer packet
  if (oPacket.IsValid()) {
    PIn_ReplySegment oSegment = oPacket.GetFirstSegment ();
    if (oSegment.ErrorCode() == 0) {
      PIn_Part oPart   = oSegment.FindPart(sp1pk_data);

      if (oPart.IsValid()) {
        PIn_DataPart                   oDataPart(oPart);
        PIn_DataPart::ConversionNeeded oConversion = PIn_DataPart::ConvertUnknown;
        const char *                   pValue      = NULL;
        tsp00_Int4                     nLength     = 0;

        switch (oField.oType) {
          case DBMSrv_SQLField::typeInt:
            oField.iValue = 0;
            oField.bNull = oDataPart.IsNull(oField.pInfo);
            if (!oField.bNull) {
              if (!oDataPart.GetValueAsInt(oField.pInfo, oField.iValue)) {
                return false;
              } // end if
            } // end if
            break;
          case DBMSrv_SQLField::typeString:
            oField.sValue = "";
            oField.bNull = oDataPart.IsNull(oField.pInfo);
            if (!oDataPart.GetValueAsChar(oField.pInfo, pValue, nLength, oConversion)) {
              return false;
            } // end if
//            if (nLength > 0) {
              switch (oSegment.GetRawHeader()->sp1r_function_code()) {
                case csp1_administrator_fc:
                case csp1_diagnose_fc:
                  oField.sValue.ConvertFromASCII_Latin1((Tools_DynamicUTF8String::ASCIIConstPointer) pValue, (Tools_DynamicUTF8String::ASCIIConstPointer) (pValue + nLength));
                  break;
                default:
                  switch (oConversion) {
                    case PIn_DataPart::ConvertAlways:
                      oField.sValue.ConvertFromUCS2_Unaligned_Swap((Tools_DynamicUTF8String::UCS2Char *) pValue, (Tools_DynamicUTF8String::UCS2Char *) (pValue + (nLength*2)));
                      break;
                    case PIn_DataPart::ConvertNever:
                      oField.sValue.ConvertFromASCII_Latin1((Tools_DynamicUTF8String::ASCIIConstPointer) pValue, (Tools_DynamicUTF8String::ASCIIConstPointer) (pValue + nLength));
                      break;
                    case PIn_DataPart::ConvertSometimes:
                      if (this->nUnicode) {
                        oField.sValue.ConvertFromUCS2_Unaligned_Swap((Tools_DynamicUTF8String::UCS2Char *) pValue, (Tools_DynamicUTF8String::UCS2Char *) (pValue + (nLength*2)));
                      } else {
                        oField.sValue.ConvertFromASCII_Latin1((Tools_DynamicUTF8String::ASCIIConstPointer) pValue, (Tools_DynamicUTF8String::ASCIIConstPointer) (pValue + nLength));
                      } // end if
                      break;
                    default:
                      return false;
                      break;
                  } // end switch
                  break;
              } // end swicth
//            } // end if
            oField.sValue.TrimTrailing();
            break;
          default:
            return false;
            break;
        } // end switch

      } // end if
    } // end if
  } // end if

  return true;
} // end DBMSrvKnl_Session :: GetValue

/*-----------------------------------------------------------------------------*/
/*! @brief private member */
tsp1_packet * DBMSrvKnl_Session :: Receive
    (  )
{
  tsp00_ErrText  pasErrtext;
  tsp01_CommErr  nCommRc;
  SAPDB_Int4     nLength;
  
  this->pReceivePacket = NULL;

  sqlareceive (this->nSessionHandle, 
               (void**)&this->pReceivePacket,
               &nLength, 
               pasErrtext, 
               &nCommRc);

  if (nCommRc != commErrOk_esp01) {
    tsp00_ErrTextc       szErrtext;

    szErrtext.p2c(pasErrtext);

    SAPDBErr_MessageList oMsg(DBMSrv_DBMError(RTE), 0);
    SAPDBErr_MessageList oRTE(DBMSrv_ExtendedError(nCommRc), szErrtext.asCharp(), 0);
    oMsg.AppendNewMessage(oRTE);
    this->oMessageList = oMsg;
    return NULL;
  } // end if

  return pReceivePacket;
} // end DBMSrvKnl_Session :: Receive

/*-----------------------------------------------------------------------------*/
/*! @brief private member */
void DBMSrvKnl_Session :: ReadErrorText
  ( PIn_ReplySegment & oSegment )
{
    PIn_Part oPart     = oSegment.FindPart(sp1pk_errortext);
    PIn_Part oPart2    = oSegment.FindPart(sp1pk_message_list);

    if (oPart.IsValid()) {
      PIn_ErrorTextPart oErrorTextPart(oPart);
      Tools_DynamicUTF8String sError;
      if (this->nUnicode) {
        sError.ConvertFromUCS2_Unaligned_Swap((Tools_DynamicUTF8String::UCS2Char *) oErrorTextPart.ErrorText(), (Tools_DynamicUTF8String::UCS2Char *) (oErrorTextPart.ErrorText() + oErrorTextPart.ErrorLen()));
      } else {
        sError.ConvertFromASCII_Latin1((Tools_DynamicUTF8String::ASCIIConstPointer) oErrorTextPart.ErrorText(), (Tools_DynamicUTF8String::ASCIIConstPointer) (oErrorTextPart.ErrorText() + oErrorTextPart.ErrorLen()));
      } // end if

      SAPDBErr_MessageList oMsg(DBMSrv_DBMError(SQL), 0);
      SAPDBErr_MessageList oSQL(DBMSrv_ExtendedError(oSegment.ErrorCode()), sError.CharPtr(), 0);
      oMsg.AppendNewMessage(oSQL);
      if (oPart2.IsValid()) {
        PIn_MessageListPart oMsgListPart(oPart2);
        SAPDBErr_MessageList oKernelMsg = oMsgListPart.MessageList();
        if (!oKernelMsg.IsEmpty()) {
          oMsg.AppendNewMessage(oKernelMsg);
        } // end if
      } // end if
      this->oMessageList = oMsg;
    } else {
      SAPDBErr_MessageList oMsg(DBMSrv_DBMError(SQL), 0);
      SAPDBErr_MessageList oSQL(DBMSrv_ExtendedError(oSegment.ErrorCode()), "(no error text available from database kernel)", 0);
      oMsg.AppendNewMessage(oSQL);
      this->oMessageList = oMsg;
    } // end if

} // end DBMSrvKnl_Session :: ReadErrorText

/*-----------------------------------------------------------------------------*/
/*! @brief private member */
void DBMSrvKnl_Session :: Reset
    ( )
{
  this->nSessionHandle = 0;
  this->nPacketSize    = 0;
  this->pPacket        = NULL;
  this->pReceivePacket = NULL;
  this->nUnicode       = 0;
  this->szPwd.Init();
  this->szUser.Init();
  this->bConnected     = false;
  this->bAutoCommit    = false;

} // end DBMSrvKnl_Session :: Reset

/*-----------------------------------------------------------------------------*/
/*******************************************************************************/
/*-----------------------------------------------------------------------------*/

/*-----------------------------------------------------------------------------*/
/*! @brief constructor */
DBMSrv_SQLRecord :: DBMSrv_SQLRecord
    ( DBMSrvKnl_Session & aKernelSession )
    : oKernelSession(aKernelSession)
{
  this->nParamCount = this->oKernelSession.ParamCount();
  this->pParamInfo  = this->oKernelSession.ParamInfo();
} // end DBMSrv_SQLRecord :: DBMSrv_SQLRecord

/*-----------------------------------------------------------------------------*/
/*! @brief constructor */
DBMSrv_SQLRecord :: DBMSrv_SQLRecord
    ( const DBMSrv_SQLRecord  & aRecord )
    : oKernelSession(aRecord.oKernelSession)
{
  this->nParamCount = this->oKernelSession.ParamCount();
  this->pParamInfo  = this->oKernelSession.ParamInfo();
} // end DBMSrv_SQLRecord :: DBMSrv_SQLRecord

/*-----------------------------------------------------------------------------*/
/*! @brief destructor */
DBMSrv_SQLRecord :: ~DBMSrv_SQLRecord
    (  )
{
} // end DBMSrv_SQLRecord :: ~DBMSrv_SQLRecord

/*-----------------------------------------------------------------------------*/
/*! @brief assignment */
DBMSrv_SQLRecord & DBMSrv_SQLRecord :: operator = 
      ( const DBMSrv_SQLRecord & aRecord )
{
  this->oKernelSession = aRecord.oKernelSession;
  this->nParamCount    = this->oKernelSession.ParamCount();
  this->pParamInfo     = this->oKernelSession.ParamInfo();
  return *this;
} // end DBMSrv_SQLRecord :: operator =

/*-----------------------------------------------------------------------------*/
/*! @brief get data */
tsp00_Int4 DBMSrv_SQLRecord :: fieldAsInt ( const tsp00_Int4 nField  ) 
{
  if (nField <= this->nParamCount && nField > 0) {
    DBMSrv_SQLField oField(&this->pParamInfo[nField-1], DBMSrv_SQLField::typeInt);

    if (this->oKernelSession.GetValue(nField, oField)) {
      return oField.iValue;
    } // end if
  } // end if

  return 0;
} // end DBMSrv_SQLRecord :: fieldAsInt

/*-----------------------------------------------------------------------------*/
/*! @brief get data */
tsp00_Int4 DBMSrv_SQLRecord :: fieldAsInt ( const Tools_DynamicUTF8String & szField  ) 
{
  return fieldAsInt(fieldNumber(szField));
} // end DBMSrv_SQLRecord :: fieldAsInt

/*-----------------------------------------------------------------------------*/
/*! @brief get data */
Tools_DynamicUTF8String DBMSrv_SQLRecord :: fieldAsChar 
      ( const tsp00_Int4 nField,
        const char     cStringQuote)
{
  if (nField <= this->nParamCount && nField > 0) {
    DBMSrv_SQLField oField(&this->pParamInfo[nField-1], DBMSrv_SQLField::typeString);

    if (this->oKernelSession.GetValue(nField, oField)) {
      if (cStringQuote != 0 && !oField.bNull && this->IsString(oField.pInfo->sp1i_data_type)) {
        if (oField.sValue.Length() == 0) {
          oField.sValue.Append(cStringQuote);
        } else {
          oField.sValue.Insert(0, cStringQuote);
        } // end if
        oField.sValue.Append(cStringQuote);
      } // end if
      return oField.sValue;
    } // end if
  } // end if

  return "";
} // end DBMSrv_SQLRecord :: fieldAsChar

/*-----------------------------------------------------------------------------*/
/*! @brief get data */
Tools_DynamicUTF8String DBMSrv_SQLRecord :: fieldAsChar 
      ( const Tools_DynamicUTF8String & szField,
        const char                      cStringQuote)
{
  return fieldAsChar(fieldNumber(szField));
} // end DBMSrv_SQLRecord :: fieldAsChar

/*-----------------------------------------------------------------------------*/
/*! @brief get data */
tsp00_DataType DBMSrv_SQLRecord :: fieldType ( const tsp00_Int4 nField  ) 
{
  tsp00_DataType oDataType;

  if ((nField <= this->nParamCount) && (nField > 0) && (this->pParamInfo != NULL)) {
    oDataType = this->pParamInfo[nField-1].sp1i_data_type;
  } else {
    oDataType.becomes(dunknown);
  } // end if

  return oDataType;
} // end DBMSrv_SQLRecord :: fieldType

/*-----------------------------------------------------------------------------*/
/*! @brief get data */
tsp00_DataType DBMSrv_SQLRecord :: fieldType ( const Tools_DynamicUTF8String & szField  ) 
{
  return fieldType(fieldNumber(szField));
} // end DBMSrv_SQLRecord :: fieldType

/*-----------------------------------------------------------------------------*/
/*! @brief get data */
bool DBMSrv_SQLRecord :: isNull ( const tsp00_Int4 nField  ) 
{
  if (nField <= this->nParamCount && nField > 0) {
    DBMSrv_SQLField oField(&this->pParamInfo[nField-1], DBMSrv_SQLField::typeString);

    if (this->oKernelSession.GetValue(nField, oField)) {
      return oField.bNull;
    } // end if
  } // end if

  return false;;
} // end DBMSrv_SQLRecord :: isNull

/*-----------------------------------------------------------------------------*/
/*! @brief get data */
bool DBMSrv_SQLRecord :: isNull ( const Tools_DynamicUTF8String &  szField ) 
{
  return this->isNull(this->fieldNumber(szField));
} // end DBMSrv_SQLRecord :: isNull

/*-----------------------------------------------------------------------------*/
/*! @brief get data */
bool DBMSrv_SQLRecord :: exists ( const tsp00_Int4 nField  ) 
{
  return (nField <= this->nParamCount && nField > 0);
} // end DBMSrv_SQLRecord :: exists

/*-----------------------------------------------------------------------------*/
/*! @brief get data */
bool DBMSrv_SQLRecord :: exists ( const Tools_DynamicUTF8String &  szField  ) 
{
  return this->exists(this->fieldNumber(szField));
} // end DBMSrv_SQLRecord :: exists

/*-----------------------------------------------------------------------------*/
/*! @brief get data */
tsp00_Int4 DBMSrv_SQLRecord :: fieldNumber ( const Tools_DynamicUTF8String &  szField  ) 
{
  tsp00_Int4  nField = 0;
  int         i = 1;
  
  while (nField == 0 && i <= this->nParamCount) {
    nField = (szField == this->fieldName(i)) ? i : 0;
    ++i;
  } // end if

  return nField;
} // end DBMSrv_SQLRecord :: fieldNumber

/*-----------------------------------------------------------------------------*/
/*! @brief get data */
Tools_DynamicUTF8String DBMSrv_SQLRecord :: fieldName ( const tsp00_Int4 nField  ) 
{
  return this->oKernelSession.FieldName(nField);
} // end DBMSrv_SQLRecord :: fieldName

/*-----------------------------------------------------------------------------*/
/*! @brief get data */
tsp00_Int4 DBMSrv_SQLRecord :: fields ( ) 
{
  return this->nParamCount;
} // end DBMSrv_SQLRecord :: fields

/*-----------------------------------------------------------------------------*/
/*! @brief check for string */
bool DBMSrv_SQLRecord :: IsString 
  ( tsp00_DataType aDataType )
{
  bool bRc = false;

  switch(aDataType) {
    // Had I hit all data types???
    case dcha:
    case dunicode:
    case dvarchara:
    case ddate:
    case dtime:
    case dtimestamp:
    case dstra:
      bRc = true;
  } // end switch

  return bRc;

} // DBMSrv_SQLRecord :: IsString

/*-----------------------------------------------------------------------------*/
/*! @brief get record */
bool DBMSrv_SQLRecord :: getNextRecord
  ( bool & bEnd )
{
  bool bReturn = this->oKernelSession.FetchRecord(bEnd, false);

  if (bReturn && !bEnd) {
    this->nParamCount = this->oKernelSession.ParamCount();
    this->pParamInfo  = this->oKernelSession.ParamInfo();
  } // end if

  return bReturn;
} // end if
