/*!
  -----------------------------------------------------------------------------
  module: vls29_dataupdate.cpp
  -----------------------------------------------------------------------------

  responsible:  d033893

  special area: Loader

  description:  dataupdate

  version:      7.5.
  -----------------------------------------------------------------------------

    ========== licence begin  GPL
    Copyright (c) 1997-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


*/

#include "gls00.h"
#include "hls01.h"
#include "hls03.h"
#include "hls04.h"
#include "hls041.h"
#include "hls08_long.h"
#include "hls13.h"
#include "hls15.h"
#include "hls16_condition.h"
#include "hls18.h"
#include "hls20.h"
#include "hls29_dataupdate.h"
#include "hls30.h"
#include "hls99.h"
#include "hls98msg.h"


static tsp00_Int4
ls29_InitDatUpdCmd(tls00_DBInfo            *pDBInfo,
                   tls00_TransformationCmd *pTransformationCmd,
                   tls00_DatUpdRec         *pDatUpdRec,
                   tsp00_Addr              errText);

static tsp00_Longint
ls29_InitDatUpdRec(tls00_DBInfo             *pDBInfo,
                   tls00_TransformationCmd  *pTransformationCmd,
                   tls00_DatUpdRec          *&pDatUpdRec,
                   tsp00_Addr               errText);


/*
  -----------------------------------------------------------------------------
  function:     ls29_ExecDatUpdCmd
  -----------------------------------------------------------------------------
  description:  main loop of dataupdate command
                terminated by:
                datasource reached eof
                more than maxerrorcount occured during processing

  arguments:    pDBInfo     [IN]    - A pointer to a structure that contains all
                                      information on the running session and the
                                      database connected to.
                pTransformationCmd  [IN]    - A pointer to a structure that contains all
                                      information on the dataupdate command given
                                      by the user
                pDatUpdRec  [IN]    - A pointer to a structure that contains some
                                      additional information for processing the
                                      dataupdate command
                errText     [OUT]   - errText
                
  returnvalue:  errOK_els00         - in case of NO errors
  -----------------------------------------------------------------------------
*/
static tsp00_Int4
ls29_ExecDatUpdCmd(tls00_DBInfo           *  pDBInfo,
                   tls00_TransformationCmd*  pTransformationCmd,
                   tls00_DatUpdRec        *& pDatUpdRec,
                   tsp00_Addr             errText);


// record fields
static tsp00_Longint
ls29_GetRecFields(tls00_TransformationCmd   *pTransformationCmd,
                  tls00_DatUpdRec           *pDatUpdRec,
                  tsp1_sqlmode_Enum         SQLMode,
                  tsp00_Addr                errText);


// Recovery
/*
  -----------------------------------------------------------------------------
  function:     ls29_LoggingDatPartBuf
  -----------------------------------------------------------------------------
  description:  Checks a receive  packet for error. In case of NO ERROR the 
                iRecCount, bPutVal and PartBufSize in order interface packet are reinitialized.
    
  arguments:    pSqlPacket  [IN]     - packet to check
                pDatUpdRec  [IN]     - structure with information on
                                       processing the dataload command
                iRecCount   [IN/OUT] - count of rows sent to kernel for which
                                       the error check has to be performed
                iErrorPos   [OUT]    - in case of error indicating the erroneous
                                       record in packet
                errText     [OUT]    - error text

  returnvalue:  errOK_els00         - in case of NO errors
                kernel error while processing data

                In case of no errors the iRecCount is set to 0. The values for
                LastCommittedLine, Count of rejected and count of inserted rows
                are adapted.
                In case of error the function writes an error message.
  -----------------------------------------------------------------------------
*/
static tsp00_Int4
ls29_LoggingDatPartBuf(tsp1_packet*       pSqlPacket,
                       tls00_DatUpdRec*   pDatUpdRec,
                       tsp00_Int4        &iRecCount,
                       tsp00_Int4        &iErrorPos,
                       tsp00_Addr         errText);

static void
ls29_FreeDBInfo(tls00_DBInfo* pDBInfo, tls00_DatUpdRec* pDatUpdRec);

static void
ls29_FreeDatUpdRec(tls00_DatUpdRec *&pDatUpdRec, tsp00_Addr errText);

static void
ls29_FreeDatUpdCmd( tls00_TransformationCmd* pTransformationCmd);


/*
  -----------------------------------------------------------------------------
  function:     ls29_GetNewDatPartBuf
  -----------------------------------------------------------------------------
  description:  Build as many database records as fit into one packet
                This function builds database record and writes it to a part data buffer
                that will be sent by a msgtype: execute

  arguments:    pDBInfo     [IN]    - A pointer to a structure that contains all
                                      information on the running session and the
                                      database connected to.
                pTransformationCmd  [IN]    - A pointer to a structure that contains all
                                      information on the dataupdate command given
                                      by the user
                pDatUpdRec  [IN]    - A pointer to a structure that contains some
                                      additional information for processing the
                                      dataupdate command
                iRecCount   [OUT]   - Count of records stored in pDatPartBuf
                bPutVal     [OUT]   - Indicates that a long column of the last
                                      record in pDatPartBuf has to be sent
                                      using the msgtype putval :
                errText     [OUT]   - errText

  returnvalue:  errOK_els00         - in case of NO errors
                error reading file
                error in processing data greater than maxerrorcount
                some other errors   - in case of errors
  -----------------------------------------------------------------------------
*/
static tsp00_Longint
ls29_GetNewDatPartBuf(tls00_DBInfo            *pDBInfo,
                      tls00_TransformationCmd *pTransformationCmd,
                      tls00_DatUpdRec         *pDatUpdRec,
                      tsp00_Int4              &iRecCount ,
                      bool                    &bPutVal,
                      tsp00_Addr              ErrText);


// Definition - Globale functions

/* -----------------------------------------------------------------------------
   ls29ExecColumnUpdate
/-------------------------------------------------------------------------------*/
tsp00_Int4
ls29ExecColumnUpdate(MetaDataDef *pMetaDataDef, tls00_DBInfo *pDBInfo, tsp00_Addr errText)
{
    ROUTINE_DBG_MEO00 ("ls29ExecColumnUpdate");

    tsp00_Longint    rc   = errOK_els00;

    TransformationDef       * pTransformationDef  = pMetaDataDef->getTransformationModel();
    tls00_TransformationCmd * pTransformationCmd  = pTransformationDef->getTransformationCmd();

    tls00_DatUpdRec *pDatUpdRec = NULL;

    // interpret <dataupdate statement>::=
    // DATAUPDATE TABLE <table_spec> <acc_column_spec_mlt> <set_column_spec_mlt> <infile_spec> <longfile_spec_mlt>;

    rc = ls29_InitDatUpdRec(pDBInfo,pTransformationCmd,pDatUpdRec,errText);
    if (errOK_els00 == rc)
    {
        rc = ls29_InitDatUpdCmd(pDBInfo,pTransformationCmd,pDatUpdRec,errText);
        if (errOK_els00 == rc)
        {
            rc = ls29_ExecDatUpdCmd(pDBInfo,pTransformationCmd,pDatUpdRec,errText);
        }
    }

    if ( false == pTransformationCmd->trInternal_ls00 )
    {
        ls29_FreeDBInfo(pDBInfo,pDatUpdRec);
        LoaderMessages::Instance()->ls98AppendStatusToString(layDataLoad_els98, errText, statUpdatedInvalidRows_els98,
                                                                                         STATIC_CAST(SAPDB_Int8, pDatUpdRec->duprUpdatedRows_ls00),
                                                                                         STATIC_CAST(SAPDB_Int8, pDatUpdRec->duprRejectedRows_ls00));
    }

    ls29_FreeDatUpdCmd(pTransformationCmd);
    ls29_FreeDatUpdRec(pDatUpdRec,errText);

    return STATIC_CAST(tsp00_Int4, rc);
}
//ls29ExecColumnUpdate()


/*-----------------------------------------------------------------------------
    ls29_ExecDatUpdCmd
/-----------------------------------------------------------------------------*/
static tsp00_Int4
ls29_ExecDatUpdCmd(tls00_DBInfo             *pDBInfo,
                   tls00_TransformationCmd  *pTransformationCmd,
                   tls00_DatUpdRec          *&pDatUpdRec,
                   tsp00_Addr               errText)
{
    ROUTINE_DBG_MEO00 ("ls29_ExecuteDatUpdCmd");

    LoaderMessages *pMsgInstance = LoaderMessages::Instance();
    tsp00_Longint    rc           = errOK_els00;

    // msgtype : execute
    // part    : data
    tsp1_part    *pDataPart  = NULL;
    tsp1_packet  *pSqlSndPkt = pDBInfo->dbiPktSndList_ls00[0];
    ls04GetPart(pSqlSndPkt,sp1pk_data,pDataPart);


    tls00_DataPartHandling *pPartHandling = &pDatUpdRec->duprDataPartHandling_ls00;

    // msgtype : putval
    // part    : longdata
    bool          bPutVal   = false;

    // record per packet
    tsp00_Int4    iRecCount = 0;

    // main loop
    while ( (errOK_els00 == rc)                                                    &&
            (EOF_LS00 != pDatUpdRec->duprpvFile->vfFilePos_ls00.lnuRemainder_ls00) &&
            (pDatUpdRec->duprRejectedRows_ls00 < pDBInfo->dbiSession_ls00.siMaxAdmissibleErrors) )
    {
        //*
        //*     Before updating we check for cancel request
        //*
        rc = ls01CheckForCancel(pDBInfo->dbiSession_ls00.sipCancelByte_ls00);
        if (errOK_els00 != rc)
        {
            pMsgInstance->ls98Msg(layDataUpdate_els98, errText, errCancelRequest_els98);
        }

        // dataSource access:

        // message Type: execute
        if (errOK_els00 == rc)
        {
            rc = ls29_GetNewDatPartBuf(pDBInfo, pTransformationCmd, pDatUpdRec, iRecCount, bPutVal, errText);
            if (errOK_els00 == rc)
            {
                // message Type: putval
                // process long columns of last record
                if (true == bPutVal)
                {
                    rc = ls08ExecPutVal(pPartHandling->dphBuffer_ls00,
                                        pDBInfo,
                                        pDatUpdRec->duprLongExecInfo_ls00,
                                        pDatUpdRec->duprpVecLongDescriptor_ls00,
                                        pTransformationCmd->trColSpec_ls00,
                                        pDatUpdRec->duprPartAttr_ls00,
                                        pDatUpdRec->duprTableDescription_ls00,
                                        pDatUpdRec->duprDataSource_ls00.pdasCodePage_ls00,
                                        errText);
                    if (errOK_els00 != rc)
                    {
                        ++pDatUpdRec->duprRejectedRows_ls00;
                        --pDatUpdRec->duprUpdatedRows_ls00;

                        // In case there fits only one record into the order interface packet and this one
                        // record was erroneous, the counter for last committed value must not be changed
                        if (iRecCount > 1)
                        {
                            pDatUpdRec->duprLastCommLine_ls00 = pPartHandling->dphRecordNumbers_ls00[iRecCount - 2];
                        }

                        pMsgInstance->ls98Msg(layDataUpdate_els98, errText, errAtRow_els98,
                                                                            pPartHandling->dphRecordNumbers_ls00[iRecCount - 1]);
                        if(pDatUpdRec->duprRejectedRows_ls00 >= pDBInfo->dbiSession_ls00.siMaxAdmissibleErrors)
                        {
                            rc = msgTableNotImport_els98;
                        }
                        else
                        {
                            errText[0] = '\0';
                        }
                    }
                    bPutVal = false;
                }

                iRecCount = 0;
            }
        }   // end if (errOK_els00 == rc)

        // If everything went ok up to this point - commit and reinitialize
        if (errOK_els00 == rc)
        {
            // Commit
            rc = ls15RSCommit(pDBInfo, errText);

            // request next or last SQLPacket
            pSqlSndPkt = pDBInfo->dbiPktSndList_ls00[0];
            memset(pSqlSndPkt, '\0', pDBInfo->dbiPktSize_ls00);
            SAPDB_memcpy((char*)&pSqlSndPkt->sp1_header, pDatUpdRec->duprpPktDatPartHeader.strAddr_ls00, pDatUpdRec->duprpPktDatPartHeader.strLeng_ls00);

            // partattr =  nextpacket or lastpacket
            ls04SetPartAttribute(pDataPart, pDatUpdRec->duprPartAttr_ls00);
        }

    }   // end while ( (EOF_LS00 != pDatUpdRec->duprpvFile->vfFilePos_ls00.lnuRemainder_ls00) && ...




    if (0 == pDatUpdRec->duprRecordCount_ls00)
    {
        pMsgInstance->ls98Msg(layDataUpdate_els98, errText, msgEmptyDataFile_els98, pDatUpdRec->duprpvFile->vfFileName_ls00);
        rc = msgEmptyDataFile_els98;
    }

    return STATIC_CAST(tsp00_Int4, rc);
}
// ls29_ExecDatUpdCmd()


/* -----------------------------------------------------------------------------
   ls29_GetNewDatPartBuf
/------------------------------------------------------------------------------*/
tsp00_Longint
ls29_GetNewDatPartBuf(tls00_DBInfo             *pDBInfo   ,
                      tls00_TransformationCmd  *pTransformationCmd ,
                      tls00_DatUpdRec          *pDatUpdRec,
                      tsp00_Int4               &iRecCount ,
                      bool                     &bPutVal,
                      tsp00_Addr               errText )
{
    ROUTINE_DBG_MEO00 ("ls29_GetNewDatPartBuf");

    LoaderMessages *pMsgObj = LoaderMessages::Instance();
    
    tsp00_Longint    rc     = errOK_els00;
    tsp00_Int4       rcREAD = errOK_els00;

    tsp00_Int4      iRecord        = iRecCount ;
    tsp00_Int4      iDatPartBufLen = 0;
    SAPDB_Bool      bOfNoInterest  = SAPDB_TRUE;

    tls00_String    DataRecord;
    DataRecord.strAddr_ls00                 = STATIC_CAST(char*, pDatUpdRec->duprDataSource_ls00.dasInputBuffer.pBufPtr_ls00);

    tls00_String           *pRecFields      = pDatUpdRec->duprDataSource_ls00.dasConvertedData;

    tls00_DataPartHandling *pPartHandling   = &pDatUpdRec->duprDataPartHandling_ls00;
    tls00_Buffer           *pDataPartBuffer = &pDatUpdRec->duprDataPartHandling_ls00.dphBuffer_ls00;

    pDatUpdRec->duprPartAttr_ls00.becomes(sp1pa_next_packet);

    // get records of a packet
    for (iRecord;
         ( (iRecord                        <  pDatUpdRec->duprMaxRowsPPckt_ls00 )   &&
           (pDataPartBuffer->lBufSize_ls00 >= pPartHandling->dphRecordLength_ls00 ) &&
           (errOK_els00 == rcREAD) && (errOK_els00 == rc) &&
           (false == bPutVal ) );
         ++iRecord)
    {
        // get record from datasource
        rcREAD = ls20ReadData(pDatUpdRec->duprpvFile,
                              &pTransformationCmd->trDataFile_ls00.fsFormat_ls00,
                              &pDatUpdRec->duprPattern_ls00,
                              NULL,
                              &pDatUpdRec->duprDataSource_ls00.dasInputBuffer,
                              &bOfNoInterest,
                              (0 == pDatUpdRec->duprRecordCount_ls00),
                              errText);
        if (rcREAD < 0)
        {
            // following values may happen:
            // - STOP_LAST_DATA_LS00    --> process read record and then stop processing
            // - STOP_NOMORE_DATA_LS00  --> nothing more to process - get outa here
            // - error code             --> nothing more to process - get outa here
            if ( (STOP_NOMORE_DATA_LS00 != rcREAD) && (STOP_LAST_DATA_LS00 != rcREAD) )
            {
                rc = rcREAD;
            }

            pDatUpdRec->duprPartAttr_ls00.becomes(sp1pa_last_packet);  // Last data in any case
            break;
        }
        if ( NULL != pTransformationCmd->trTable_ls00.tsCondSpec_ls00 )
        {
            DataRecord.strLeng_ls00 = pDatUpdRec->duprDataSource_ls00.dasInputBuffer.lBufPos_ls00;
            if ( false == ls16CheckCondition(*pTransformationCmd->trTable_ls00.tsCondSpec_ls00,
                                             DataRecord,
                                             pTransformationCmd->trDataFile_ls00.fsFormat_ls00) )
            {
                --iRecord;
                continue;
            }
        }
        ++pDatUpdRec->duprRecordCount_ls00;

        // get fields from record
        rc = ls29_GetRecFields(pTransformationCmd, pDatUpdRec, pDBInfo->dbiSession_ls00.siSQLMode_ls00, errText);
        if ( errOK_els00 == rc )
        {
            pPartHandling->dphRecordNumbers_ls00[iRecord] = pDatUpdRec->duprRecordCount_ls00;

            //*
            //* set LONG value descriptions
            //*
            pDatUpdRec->duprLongExecInfo_ls00.dliFinishedNNLongs_ls00 = 0;
            pDatUpdRec->duprLongExecInfo_ls00.dliCntNNLongs_ls00      = 0;

            // write record to datapart
            rc = ls20BuildRecord(&pDatUpdRec->duprDataSource_ls00,
                                 pDataPartBuffer,
                                 &pDatUpdRec->duprTableDescription_ls00,
                                 &pTransformationCmd->trColSpec_ls00,
                                 &pDatUpdRec->duprLongExecInfo_ls00,
                                 ls00UseUnicodeOI(pDBInfo),
                                 pDatUpdRec->duprRecordCount_ls00,
                                 errText);
            if ( errOK_els00 == rc )
            {
                // adapt free and used space in buffer
                pDataPartBuffer->lBufSize_ls00 -= pPartHandling->dphRecordLength_ls00;
                pDataPartBuffer->lBufLen_ls00  += pPartHandling->dphRecordLength_ls00;

                if ( 0 == pDatUpdRec->duprLongExecInfo_ls00.dliCntNNLongs_ls00 )
                {   // save used space value for THIS record
                    pPartHandling->dphRecordSpace_ls00[iRecord] = STATIC_CAST(tsp00_Int4, pDataPartBuffer->lBufLen_ls00);
                }
                else
                {   // LONGs? Insert them here. Last inserted 'normal' record is the one for
                    // which we have to import the LONG
                    rc = ls08InsertLongs(pDatUpdRec->duprDataPartHandling_ls00,
                                         pDatUpdRec->duprLongExecInfo_ls00,
                                         pTransformationCmd->trColSpec_ls00,
                                         pDatUpdRec->duprTableDescription_ls00,
                                         pDatUpdRec->duprDataSource_ls00,
                                         bPutVal,
                                         ls00UseUnicodeOI(pDBInfo),
                                         errText);
                    if ( rc == errOK_els00 )
                    {
                        // save used space value for THIS record
                        pPartHandling->dphRecordSpace_ls00[iRecord] = STATIC_CAST(tsp00_Int4, pDataPartBuffer->lBufLen_ls00);
                    }
                    else
                    {   // Error --> undo inserted record by restoring used space of previous record
                        pDataPartBuffer->lBufSize_ls00 += pPartHandling->dphRecordLength_ls00;
                        pDataPartBuffer->lBufLen_ls00  -= pPartHandling->dphRecordLength_ls00;
                    }
                }
            }
            else
            {
                return rc;
            }
        }
        else // if ( rc == errOK_els00 )
        {
            ++pDatUpdRec->duprRejectedRows_ls00;
            if(pDatUpdRec->duprRejectedRows_ls00 >= pDBInfo->dbiSession_ls00.siMaxAdmissibleErrors)
            {
                rc = msgTableNotImport_els98;
                break;
            }
            pDatUpdRec->duprLastCommLine_ls00 = pDatUpdRec->duprRecordCount_ls00 - 1;
            iRecord -- ;
        }

        ls18RecordInit(pDatUpdRec->duprDataSource_ls00.lReadFieldsCnt_ls00,
                       pRecFields,
                       STATIC_CAST(char*, pDatUpdRec->duprDataSource_ls00.dasInputBuffer.pBufPtr_ls00),
                       pDatUpdRec->duprDataSource_ls00.dasInputBuffer.lBufPos_ls00);
    }   // end for (iRecord  ;...


    if (errOK_els00 == rc)
    {
        iRecCount = iRecord ;

        // msgtype : execute
        // part    : data
        tsp1_part    *pDataPart  = NULL;
        tsp1_packet  *pSqlSndPkt = pDBInfo->dbiPktSndList_ls00[0];
        ls04GetPart(pSqlSndPkt,sp1pk_data,pDataPart);

        // dataBuffer exchange: 1.Chance
        pDataPart->sp1p_arg_count() = iRecCount;

        if ( (pDatUpdRec->duprPartAttr_ls00 == sp1pa_last_packet ) && (pDataPart->sp1p_attributes().includes(sp1pa_last_packet) ) == false  )
        {
            ls04AddPartAttribute(pDataPart, pDatUpdRec->duprPartAttr_ls00);
        }

        rc = ls04BufToPart(pDataPart, REINTERPRET_CAST(char*, pDataPartBuffer->pBufPtr_ls00), STATIC_CAST(tsp00_Int4, pDataPartBuffer->lBufLen_ls00));
        if ( errOK_els00 == rc )
        {
            rc = ls04FinishPart (pSqlSndPkt, pDataPart);
        }
        if ( rc != errOK_els00 )
        {
            return rc;
        }

        char szErr[MAX_REPLY_LENGTH_LS00];
        szErr[0] = 0;
        tsp00_Int4 lErrPos = 0;
        rc = ls03ProcessSQLPacket(pDBInfo, 0, lErrPos, szErr);
        if ( rc != errOK_els00)
        {
            pMsgObj->ls98PrintMessage(layDataUpdate_els98, errAtRow_els98, pPartHandling->dphRecordNumbers_ls00[lErrPos - 1]);
            pMsgObj->ls98Msg(layDataUpdate_els98, errText, errSimpleSQL_els98, szErr);

            return rc;
        }

        // dataBuffer validation

        tsp00_Int4 iErrorPos = 0;

        rc = ls29_LoggingDatPartBuf(pDBInfo->dbiPktRcvList_ls00[0], pDatUpdRec, iRecCount, iErrorPos, errText);
        if ( errOK_els00 != rc )
        {
            if(pDatUpdRec->duprRejectedRows_ls00 >= pDBInfo->dbiSession_ls00.siMaxAdmissibleErrors)
            {
                // dataBuffer exchange: No Chance
                rc = msgTableNotImport_els98;
                return rc;
            }
            else
            {
                // dataBuffer exchange: Next Chance
                rc = errOK_els00;
                errText[0] = '\0';
                ls20Recover(&pDatUpdRec->duprDataPartHandling_ls00,
                            pDatUpdRec->duprLongColCnt_ls00,
                            &pDatUpdRec->duprTableDescription_ls00,
                            iRecCount,
                            iErrorPos,
                            bPutVal);

                // request next or last SQLPacket
                pSqlSndPkt = pDBInfo->dbiPktSndList_ls00[0];
                memset(pSqlSndPkt, '\0', pDBInfo->dbiPktSize_ls00);
                SAPDB_memcpy((char*) &pSqlSndPkt->sp1_header, pDatUpdRec->duprpPktDatPartHeader.strAddr_ls00, pDatUpdRec->duprpPktDatPartHeader.strLeng_ls00);
                // partattr =  nextpacket or lastpacket
                ls04SetPartAttribute(pDataPart, pDatUpdRec->duprPartAttr_ls00);

                rc = ls29_GetNewDatPartBuf(pDBInfo, pTransformationCmd , pDatUpdRec, iRecCount, bPutVal, errText);
            }
        }   // end if ( rc != errOK_els00 )
    }   // end if (errOK_els00 == rc)

    return rc;
}
// ls29_GetNewDatPartBuf()


/*-----------------------------------------------------------------------------
    ls29_LoggingDatPartBuf
/-----------------------------------------------------------------------------*/
static tsp00_Int4
ls29_LoggingDatPartBuf(tsp1_packet     *pSqlRcvPkt,
                       tls00_DatUpdRec *pDatUpdRec,
                       tsp00_Int4      &iRecCount ,
                       tsp00_Int4      &iErrorPos,
                       tsp00_Addr       errText)
{
    ROUTINE_DBG_MEO00 ("ls29_LoggingDatPartBuf");

    LoaderMessages *pMsgInstance = LoaderMessages::Instance();
    tsp00_Int4       rc           = errOK_els00;

    tls00_DataPartHandling *pHandling = &pDatUpdRec->duprDataPartHandling_ls00;

    tsp00_Int4  ErrRecordNr         = 0;
    char        pszTmpErrText[256];
    pszTmpErrText[0] = 0;

    rc = ls04RcFromPacket(pSqlRcvPkt, pszTmpErrText, iErrorPos);

    if ( rc == errOK_els00  )
    {
        tsp00_Int4 lResultCount = 0;

        rc = ls04GetResultCount(pSqlRcvPkt, NULL, lResultCount);

        // reporting
        pDatUpdRec->duprUpdatedRows_ls00 = lResultCount;        // kernel summarizes the processed records
        if (iRecCount > 0)
        {
            // Nothing sent - nothing committed
            pDatUpdRec->duprLastCommLine_ls00 = pDatUpdRec->duprDataPartHandling_ls00.dphRecordNumbers_ls00[iRecCount - 1];
        }

        // initializing
        pHandling->dphBuffer_ls00.lBufSize_ls00 = pHandling->dphBuffer_ls00.lBufSize_ls00 + pHandling->dphBuffer_ls00.lBufLen_ls00;
        pHandling->dphBuffer_ls00.lBufLen_ls00  = 0;
    }
    else
    {
        // rc == 100 : Row not found (Table empty or no match for all updates in pDatPartBuf )
        // rc == 200 : Duplicate Key

        ErrRecordNr = pHandling->dphRecordNumbers_ls00[iErrorPos - 1];

        pMsgInstance->ls98PrintMessage(layDataUpdate_els98, errAtRow_els98, ErrRecordNr);
        pMsgInstance->ls98Msg         (layDataUpdate_els98, errText, errSimpleSQL_els98, pszTmpErrText);

        ++pDatUpdRec->duprRejectedRows_ls00;
        pDatUpdRec->duprUpdatedRows_ls00 += iErrorPos - 1;

        if (iErrorPos != 1)
        {
            pDatUpdRec->duprLastCommLine_ls00 = pHandling->dphRecordNumbers_ls00[iErrorPos - 2];
        }

        if ( rc == 100 )
        {
            rc = errOK_els00;
        }
    }   // end else of if ( rc == errOK_els00  )

    return rc;
}
//  ls29_LoggingDatPartBuf()


/*-----------------------------------------------------------------------------
    ls29_FreeDBInfo
/-----------------------------------------------------------------------------*/
static void
ls29_FreeDBInfo(tls00_DBInfo* pDBInfo, tls00_DatUpdRec* pDatUpdRec)
{
    ROUTINE_DBG_MEO00 ("ls29_FreeDBInfo");
    LoaderMessages *pMsgInstance = LoaderMessages::Instance();

    // Print Statistic
    if ( pDBInfo->dbiSession_ls00.siAutoCommit_ls00 == true )
         pMsgInstance->ls98PrintMessage(layDataUpdate_els98, msgLastCommInputLine_els98,pDatUpdRec->duprLastCommLine_ls00);
    else
         pMsgInstance->ls98PrintMessage(layDataUpdate_els98, msgLastInsInputLine_els98, pDatUpdRec->duprLastCommLine_ls00);

    pMsgInstance->ls98PrintMessage(layDataUpdate_els98, msgUpdatedInvalidRows_els98, pDatUpdRec->duprUpdatedRows_ls00,
                                                                                     pDatUpdRec->duprRejectedRows_ls00);
}
// ls29_FreeDBInfo()


/*-----------------------------------------------------------------------------
  ls29_InitDatUpdRec
/-----------------------------------------------------------------------------*/
static tsp00_Longint
ls29_InitDatUpdRec(tls00_DBInfo             *pDBInfo,
                   tls00_TransformationCmd  *pTransformationCmd,
                   tls00_DatUpdRec          *&pDatUpdRec,
                   tsp00_Addr               errText)
{
    ROUTINE_DBG_MEO00 ("ls29_InitDataUpdateRec");

    tsp00_Int4 rc     = errOK_els00;
    tsp00_Int4 errPos = 0;

    pDatUpdRec = new tls00_DatUpdRec;
    memset(pDatUpdRec, 0, sizeof(tls00_DatUpdRec));

    // 0.Initialize DataUpdRec from fixed values 
    pDatUpdRec->duprResultCount_ls00[0] = 0xff;
    pDatUpdRec->duprPartAttr_ls00.becomes(sp1pa_first_packet);

    // 1.Initialize DataUpdRec from DBInfo
    pDatUpdRec->duprSwapKind_ls00 = pDBInfo->dbiOwnSwap_ls00;
    
    // 2.Initialize DataUpdRec from DataUpdCmd
    
    // Prepares the DataUpdate command as a update mass cmd
    tls00_Column*       pColumn      = NULL;
    tls00_MultColSpec*  pMultColSpec = &pTransformationCmd->trColSpec_ls00;   

    tsp00_Int4 k                = 0;
    tsp00_Int4 iKeyColCnt       = 0;
    tsp00_Int4 iWhereColCnt     = 0;
    tsp00_Int4 _lTmpSetColIndex = 0;
    bool       _bAssignment     = false;

    tsp00_Int4  iCmdLen = 0;
    tsp00_Int4  i       = 0;

    for (i = 0; i < pMultColSpec->mcsCount_ls00; ++i)
    {
        pColumn = pMultColSpec->mcsColumn_ls00[i];
        if (true == pColumn->colIsKey_ls00)
        {
             ++iKeyColCnt;
        }

        if (asUnknown_els00 != pColumn->colAssign_ls00.fasAsgnTyp_ls00)
        {
            _bAssignment = true;
            iCmdLen += pColumn->colAssign_ls00.fasAsgnLen_ls00;
        }
    }
    iWhereColCnt = pTransformationCmd->trSetColIndex_ls00 - iKeyColCnt;


    iCmdLen += (pMultColSpec->mcsCount_ls00 + 24)*sizeof(tsp00_KnlIdentifierc);
    
    char* pszCmd  = new char[iCmdLen];
    pszCmd[0]     = 0;

    //*
    //*     <update_statement>::= UPDATE [OF] <table_name> SET <set_update_clause>,...
    //*
    //*  There must be at least one SET column!
    //*
    if (0 != pTransformationCmd->trTable_ls00.tsTabOwnr_ls00.length())
    {
        k = sp77sprintf(pszCmd, iCmdLen, "UPDATE \"%s\".\"%s\" SET", pTransformationCmd->trTable_ls00.tsTabOwnr_ls00.asCharp(),
                                                                     pTransformationCmd->trTable_ls00.tsTabName_ls00.asCharp());
    }
    else
    {
        k = sp77sprintf(pszCmd, iCmdLen, "UPDATE \"%s\" SET", pTransformationCmd->trTable_ls00.tsTabName_ls00.asCharp());
    }

    tsp00_Uint4 _lValueStartPos = k;


    //Set columns start behind access/key columns in structure MultColSpec
    for (i = pTransformationCmd->trSetColIndex_ls00; i < pMultColSpec->mcsCount_ls00; ++i)
    {
        k += sp77sprintf(pszCmd+k, iCmdLen - k, " \"%s\" = ?,", pMultColSpec->mcsColumn_ls00[i]->colName_ls00.asCharp() );
    }
    --k;        // Remove last comma

    
    // [ KEY <key_spec>,...]
    if ( 0 != iKeyColCnt )
    {
        k += sp77sprintf(pszCmd+k, iCmdLen - k, " KEY "); 

        for (i = 0; i < pTransformationCmd->trSetColIndex_ls00; ++i)
        {
            if ( true == pMultColSpec->mcsColumn_ls00[i]->colIsKey_ls00 )
            {
                 k += sp77sprintf(pszCmd+k, iCmdLen - k, " \"%s\" = ?,",
                                                         pMultColSpec->mcsColumn_ls00[i]->colName_ls00.asCharp());
            }
        }
        --k;        // Remove last comma
    }

    // <search_condition> 
    if ( iWhereColCnt > 0 )
    {
        k += sp77sprintf(pszCmd+k, iCmdLen - k, " WHERE "); 

        for (i = 0; i < pTransformationCmd->trSetColIndex_ls00; ++i)
        {
             if ( ( false == pMultColSpec->mcsColumn_ls00[i]->colIsKey_ls00 ) &&
                  ( false == pMultColSpec->mcsColumn_ls00[i]->colIsSet_ls00) )

            {
                 k += sp77sprintf(pszCmd+k, iCmdLen - k, " \"%s\" = ? AND",
                                                         pMultColSpec->mcsColumn_ls00[i]->colName_ls00.asCharp());
            }
        }
        pszCmd[k - 3] = 0;      // Remove last 'AND'
    }
    else
    {
        // finish command with \0
        pszCmd[k] = 0;
    }

    // Parse statement
    // function returns parse id and shortinfo
    rc = ls13Parse(pszCmd, pDBInfo, pDatUpdRec->duprParseId_ls00, &pDatUpdRec->duprTableDescription_ls00, errText, false, true);
    

    if (errOK_els00 == rc)
    {
        _lTmpSetColIndex = pTransformationCmd->trSetColIndex_ls00;    // In case of assignments this value will be decreased
                                                                // by 1 for every assignment in qualification columns
                                                                // for later use in ls20InitDataSource
        if (true == _bAssignment)
        {
            //*
            //*     In case of assignments we need to reparse the statement to let
            //*     the kernel do the assignment upon delivery (instead of parameterizing
            //*     all values with ? we parameterize the assignments with the real value
            //*

            // <update_statement>::=

            // Reuse pszCmd

            k = _lValueStartPos;

            //Set columns start behind access/key columns in structure MultColSpec
            tls00_FieldAsgn *pAssignment = NULL;
            for (i = pTransformationCmd->trSetColIndex_ls00; i < pMultColSpec->mcsCount_ls00; ++i)
            {
                pColumn     = pMultColSpec->mcsColumn_ls00[i];
                pAssignment = &pColumn->colAssign_ls00;

                k += sp77sprintf(pszCmd+k, iCmdLen - k, " \"%s\" = ?,", pColumn->colName_ls00.asCharp());

                if (asUnknown_els00 != pAssignment->fasAsgnTyp_ls00)
                {
                    k -= 2*sizeof(char);
                    switch (pAssignment->fasAsgnTyp_ls00)
                    {
                        case asLiteral_els00:
                        {
                            if (1 == szMap_NumberDataType_ls00[pDatUpdRec->duprTableDescription_ls00.tdParamArray_ls00[i-pTransformationCmd->trSetColIndex_ls00]->piBasicInfo_ls00.fbDataType_ls00])
                            {
                                k += sp77sprintf(pszCmd+k, iCmdLen-k, "%s,", pAssignment->fasAsgnVal_ls00);
                            }
                            else
                            {
                                k += sp77sprintf(pszCmd+k, iCmdLen-k, "'%s',", pAssignment->fasAsgnVal_ls00);
                            }
                            break;
                        }
                        default:
                        {
                            k += sp77sprintf(pszCmd+k, iCmdLen-k, "%s,",
                                                                szDBFunctionNames_ls20[pAssignment->fasAsgnTyp_ls00-3]);
                        }
                    }   // end switch (pAssignment->fasAsgnTyp_ls00)
                }   // end if (asUnknown_els00 != pAssignment->fasAsgnTyp_ls00)
            }   // end for (i = pTransformationCmd->trSetColIndex_ls00; i < pMultColSpec->mcsCount_ls00; ++i)
            --k;        // Remove last comma

            // [ KEY <key_spec>,...]
            if ( 0 != iKeyColCnt )
            {
                k += sp77sprintf(pszCmd+k, iCmdLen - k, " KEY "); 
                for (i = 0; i < pTransformationCmd->trSetColIndex_ls00; ++i)
                {
                    if ( true == pMultColSpec->mcsColumn_ls00[i]->colIsKey_ls00 )
                    {
                        k += sp77sprintf(pszCmd+k, iCmdLen - k, " \"%s\" = ?,", pMultColSpec->mcsColumn_ls00[i]->colName_ls00.asCharp());
                    }
                }
                --k;        // Remove last comma
            }

            // <search_condition> 
            if ( 0 != iWhereColCnt )
            {
                tsp00_Uint4 _lSetColCnt = pMultColSpec->mcsCount_ls00 - iWhereColCnt;

                k += sp77sprintf(pszCmd+k, iCmdLen - k, " WHERE "); 
                for (i = 0; i < pTransformationCmd->trSetColIndex_ls00; ++i)
                {
                    pColumn     = pMultColSpec->mcsColumn_ls00[i];
                    pAssignment = &pColumn->colAssign_ls00;

                    if ( ( false == pColumn->colIsKey_ls00 ) && ( false == pColumn->colIsSet_ls00) )
                    {
                        if (asUnknown_els00 == pAssignment->fasAsgnTyp_ls00)
                        {
                            k += sp77sprintf(pszCmd+k, iCmdLen - k, " \"%s\" = ? AND", pColumn->colName_ls00.asCharp());
                        }
                        else
                        {
                            --_lTmpSetColIndex;

                            switch (pAssignment->fasAsgnTyp_ls00)
                            {
                                case asLiteral_els00:
                                {
                                    if (1 == szMap_NumberDataType_ls00[pDatUpdRec->duprTableDescription_ls00.tdParamArray_ls00[i+_lSetColCnt]->piBasicInfo_ls00.fbDataType_ls00])
                                    {
                                        k += sp77sprintf(pszCmd+k, iCmdLen - k, " \"%s\" = %s AND", pColumn->colName_ls00.asCharp(),
                                                                                                    pAssignment->fasAsgnVal_ls00);
                                    }
                                    else
                                    {
                                        k += sp77sprintf(pszCmd+k, iCmdLen - k, " \"%s\" = '%s' AND", pColumn->colName_ls00.asCharp(),
                                                                                                    pAssignment->fasAsgnVal_ls00);
                                    }
                                    break;
                                }
                                default:
                                {
                                    k += sp77sprintf(pszCmd+k, iCmdLen - k, " \"%s\" = %s AND", pColumn->colName_ls00.asCharp(),
                                                                                                szDBFunctionNames_ls20[pAssignment->fasAsgnTyp_ls00-3]);
                                }
                            }   // end switch (pAssignment->fasAsgnTyp_ls00)
                        }   // end if (asUnknown_els00 != pAssignment->fasAsgnTyp_ls00)
                    }
                }
                pszCmd[k - 3] = 0;      // Remove last 'AND'
            }
            else
            {
                // finish command with \0
                pszCmd[k] = 0;
            }

        
            // Before running ls13Parse the 2nd time we have to free
            //                   pTI->tdParamArray_ls00
            // in order to avoid memory leaks
            for (tsp00_Int4 j=0; j < pDatUpdRec->duprTableDescription_ls00.tdFieldCount_ls00; ++j)
            {
                if (NULL != pDatUpdRec->duprTableDescription_ls00.tdParamArray_ls00[j])
                {
                    delete pDatUpdRec->duprTableDescription_ls00.tdParamArray_ls00[j];
                    pDatUpdRec->duprTableDescription_ls00.tdParamArray_ls00[j] = NULL;
                }
            }
            pDatUpdRec->duprTableDescription_ls00.tdFieldCount_ls00 = 0;

            // Parse statement
            // function returns parse id and shortinfo
            rc = ls13Parse(pszCmd, pDBInfo, pDatUpdRec->duprParseId_ls00, &pDatUpdRec->duprTableDescription_ls00, errText, false, true);
        }
    }   // end if ( (errOK_els00 == rc) && (true == _bAssignment) )
    
    delete [] pszCmd;
    pszCmd = NULL;

    if (errOK_els00 == rc)
    {
        tls00_TableDescription *pTD = &pDatUpdRec->duprTableDescription_ls00;
        pTD->tdTablename_ls00.Init();
        pTD->tdTablename_ls00.rawAssign(pTransformationCmd->trTable_ls00.tsTabName_ls00.asCharp());

        pDatUpdRec->duprpvFile       = new tls00_VFile;
        tls00_FileSpec  *pInFileSpec = &pTransformationCmd->trDataFile_ls00;

        pDatUpdRec->duprpvFile->vfFileType_ls00 = pInFileSpec->fsDeviceType_ls00;
        if ( dtypeTape_ls00 == pDatUpdRec->duprpvFile->vfFileType_ls00 )
        {
            pDatUpdRec->duprpvFile->vfBackupTool_ls00 = pDBInfo->dbiSession_ls00.siBackupTool_ls00;
            pDatUpdRec->duprpvFile->vfBackupId_ls00.Assign(REINTERPRET_CAST(Tools_DynamicUTF8String::ConstPointer,
                                                                            pInFileSpec->fsBackupId_ls00.bBackupIdName_ls00));
        }


        // Update long column count
        for (i = 0; i < pTD->tdFieldCount_ls00; ++i)
        {
            if (1 == szMap_LongDataType_ls00[pTD->tdParamArray_ls00[i]->piBasicInfo_ls00.fbDataType_ls00])
            {
                ++pDatUpdRec->duprLongColCnt_ls00;
            }
          
        }

        pDatUpdRec->duprLongExecInfo_ls00.dliNNLongs_ls00         = new tsp00_Int2[pTD->tdFieldCount_ls00];
        pDatUpdRec->duprLongExecInfo_ls00.dliFinishedNNLongs_ls00 = 0;
        pDatUpdRec->duprpVecLongDescriptor_ls00                   = new tsp00_LongDescriptor[pDatUpdRec->duprLongColCnt_ls00];


        tls00_DataPartHandling *pPartHandling = &pDatUpdRec->duprDataPartHandling_ls00;

        pDatUpdRec->duprRecordCount_ls00    = 0;
        pPartHandling->dphRecordLength_ls00 = ls18GetRecordLength(*pTD, true);
        pDatUpdRec->duprMaxRowsPPckt_ls00   = ( pDBInfo->dbiPktSize_ls00 -
                                               (BlockHSize_ls00 + 2*PartHSize_ls00 + sizeof(pDatUpdRec->duprResultCount_ls00) + 
                                                MAX_PARSEID_LENGTH_LS00 + 16
                                               )
                                              ) / pPartHandling->dphRecordLength_ls00;

        pDatUpdRec->duprMaxRowsPPckt_ls00    == 0 ? 1 : pDatUpdRec->duprMaxRowsPPckt_ls00;
        pPartHandling->dphRecordNumbers_ls00 = new tsp00_Int4[pDatUpdRec->duprMaxRowsPPckt_ls00];
        pPartHandling->dphRecordSpace_ls00   = new tsp00_Int4[pDatUpdRec->duprMaxRowsPPckt_ls00];
        pDatUpdRec->duprUpdatedRows_ls00     = 0;
        pDatUpdRec->duprLastCommLine_ls00    = 0;
        pDatUpdRec->duprRejectedRows_ls00    = 0;

        // 3. Init dataBuffer

        // message Type: execute
        // -> RequestWriter::InitExecute (pDatUpdRec->duprParseId_ls00)
        // -> Part RequestSegment::AddPart (sp1m_execute)
        // -> Part RequestSegment::AddPart (sp1pk_parsid)
        tls00_Buffer *pDataBuffer = &pDatUpdRec->duprDataPartHandling_ls00.dphBuffer_ls00;
    
        ls20InitializeOIPacket(pDBInfo,
                               pDatUpdRec->duprParseId_ls00,
                               pDatUpdRec->duprResultCount_ls00,
                               pDatUpdRec->duprPartAttr_ls00,
                               pDatUpdRec->duprpPktDatPartHeader,
                               pDataBuffer);
        if (errOK_els00 != rc)
        {
            LoaderMessages::Instance()->ls98Msg(layDataUpdate_els98, errText, STATIC_CAST(ErrorNumbers, rc));
        }
        else
        {
            if ( pInFileSpec->fsFormat_ls00.ffoBinary_ls00 == false )
            {
                ls30VFInitialize(*pDatUpdRec->duprpvFile,
                                 pInFileSpec->fsFileName_ls00,
                                 sp5vf_text,
                                 sp5vf_read,
                                 pInFileSpec->fsFormat_ls00.ffoCodeType_ls00);
            }
            else
            {
                ls30VFInitialize(*pDatUpdRec->duprpvFile, pInFileSpec->fsFileName_ls00);
            }

            rc = ls30VFOpen(*pDatUpdRec->duprpvFile, errText);

            if (ctUnknown_els00 == pTransformationCmd->trDataFile_ls00.fsFormat_ls00.ffoCodeType_ls00)
            {
                pTransformationCmd->trDataFile_ls00.fsFormat_ls00.ffoCodeType_ls00 = pDatUpdRec->duprpvFile->vfFileEncoding_ls00;
            }
        }


        // Fill pattern structure only if the file format is COMPRESSED
        if ( (errOK_els00 == rc) && (true == pTransformationCmd->trDataFile_ls00.fsFormat_ls00.ffoCompress_ls00) )
        {
            rc = ls18ConstructPattern(&pDatUpdRec->duprPattern_ls00,
                                      pInFileSpec->fsFormat_ls00.ffoSeperat_ls00,
                                      pInFileSpec->fsFormat_ls00.ffoDelimit_ls00,
                                      pInFileSpec->fsFormat_ls00.ffoCodeType_ls00,
                                      errText);
        }

        // Init dataSource
        pDatUpdRec->duprDataSource_ls00.dasInputBuffer.lBufLen_ls00 = 6*pDBInfo->dbiPageSize_ls00;
        ls20InitDataSourceStruct(&pDatUpdRec->duprDataSource_ls00,
                                 &pInFileSpec->fsFormat_ls00,
                                 pTD->tdFieldCount_ls00,
                                 pMultColSpec,
                                 _lTmpSetColIndex);
    }

    return rc;
}
// ls29_InitDatUpdRec()


 /*-----------------------------------------------------------------------------
  ls29_FreeDatUpdRec
/-----------------------------------------------------------------------------*/
static void
ls29_FreeDatUpdRec(tls00_DatUpdRec *&pDatUpdRec, tsp00_Addr errText)
{
    ROUTINE_DBG_MEO00 ("ls29_FreeDatUpdRec");

    tls00_TableDescription  *pTD    = &pDatUpdRec->duprTableDescription_ls00;
    tsp00_Int4              iColumn = 0;

    for (iColumn=0; iColumn < pTD->tdFieldCount_ls00; iColumn++)
    {
        if (pTD->tdParamArray_ls00[iColumn] != NULL )
        {
            delete pTD->tdParamArray_ls00[iColumn];
            pTD->tdParamArray_ls00[iColumn] = NULL;
        }
    }

    if(pDatUpdRec->duprDataPartHandling_ls00.dphRecordNumbers_ls00 != NULL)
    {
        delete [] pDatUpdRec->duprDataPartHandling_ls00.dphRecordNumbers_ls00;
        pDatUpdRec->duprDataPartHandling_ls00.dphRecordNumbers_ls00 = NULL;
    }

    if (pDatUpdRec->duprDataPartHandling_ls00.dphRecordSpace_ls00  != NULL)
    {
        delete [] pDatUpdRec->duprDataPartHandling_ls00.dphRecordSpace_ls00;
        pDatUpdRec->duprDataPartHandling_ls00.dphRecordSpace_ls00  = NULL;
    }

    if (pDatUpdRec->duprLongExecInfo_ls00.dliNNLongs_ls00 != NULL)
    {
        delete [] pDatUpdRec->duprLongExecInfo_ls00.dliNNLongs_ls00;
        pDatUpdRec->duprLongExecInfo_ls00.dliNNLongs_ls00 = NULL;
    }

    if (pDatUpdRec->duprpVecLongDescriptor_ls00 != NULL)
    {
        delete [] pDatUpdRec->duprpVecLongDescriptor_ls00;
        pDatUpdRec->duprpVecLongDescriptor_ls00 = NULL;
    }
    if (NULL != pDatUpdRec->duprDataPartHandling_ls00.dphBuffer_ls00.pBufPtr_ls00)
    {
        delete [] (STATIC_CAST(unsigned char*, pDatUpdRec->duprDataPartHandling_ls00.dphBuffer_ls00.pBufPtr_ls00));
        pDatUpdRec->duprDataPartHandling_ls00.dphBuffer_ls00.pBufPtr_ls00 = NULL;
    }

    if ( pDatUpdRec->duprpvFile  != NULL  )
    {
         ls30VFClose(*pDatUpdRec->duprpvFile,errText);
         delete pDatUpdRec->duprpvFile  ;
         pDatUpdRec->duprpvFile  = NULL ;
    }
    if (NULL != pDatUpdRec->duprpPktDatPartHeader.strAddr_ls00)
    {
        delete [] pDatUpdRec->duprpPktDatPartHeader.strAddr_ls00;
        pDatUpdRec->duprpPktDatPartHeader.strAddr_ls00 = NULL ;
    }

    tls00_DataSource *pSource = &pDatUpdRec->duprDataSource_ls00;

    // Delete converted data buffer
    ls18RecordDestructor(pTD->tdFieldCount_ls00, pSource->dasConvertedData);

    // Delete remaining members of struct tls00_DataSource
    if (NULL != pSource->lReadPos_ls00)
    {
        delete [] pSource->lReadPos_ls00;
        pSource->lReadPos_ls00 = NULL;
    }
    if (NULL != pSource->plDataToColIndex_ls00)
    {
        delete [] pSource->plDataToColIndex_ls00;
        pSource->plDataToColIndex_ls00 = NULL;
    }
    if (NULL != pSource->plDataToParamIndex_ls00)
    {
        delete [] pSource->plDataToParamIndex_ls00;
        pSource->plDataToParamIndex_ls00 = NULL;
    }
    pSource = NULL;

    // delete pattern matching structure
    ls18DestructPattern(&pDatUpdRec->duprPattern_ls00);


    delete pDatUpdRec;
    pDatUpdRec = NULL;
}
// ls29_FreeDatUpdRec()


/*-----------------------------------------------------------------------------
    ls29_InitDatUpdCmd
/-----------------------------------------------------------------------------*/
static tsp00_Int4
ls29_InitDatUpdCmd(tls00_DBInfo            *pDBInfo,
                   tls00_TransformationCmd *pTransformationCmd,
                   tls00_DatUpdRec         *pDatUpdRec,
                   tsp00_Addr              errText)
{
    ROUTINE_DBG_MEO00 ("ls29_InitDatUpdCmd");

    LoaderMessages *pMsgObj = LoaderMessages::Instance();
    tsp00_Int4       rc      = errOK_els00;

    //  1. Init tls00_TableSpec
    tls00_FileFormat *pInFileFormat = &pTransformationCmd->trDataFile_ls00.fsFormat_ls00;

    // <table_spec> ::= <table_name> <if_condition>
    if ( pTransformationCmd->trTable_ls00.tsCondSpec_ls00 )
    {
        rc = ls16ConvertCondition(*pTransformationCmd->trTable_ls00.tsCondSpec_ls00,
                                  pDBInfo->dbiOwnSwap_ls00,
                                  *pInFileFormat,
                                  errText );
    }
    if ( rc != errOK_els00 )
         return rc;

    // 2. Init tls00_MultColSpec
    tls00_TableDescription *pTD          = &pDatUpdRec->duprTableDescription_ls00;
    tls00_MultColSpec      *pMultColSpec = &pTransformationCmd->trColSpec_ls00;
    tls00_Column           *pColumn      = NULL;
    tls00_FieldBasics      *pFieldBasic  = NULL;

    for (tsp00_Int4 i=0; i < pTD->tdFieldCount_ls00; ++i)
    {
        pFieldBasic = &pTD->tdParamArray_ls00[pDatUpdRec->duprDataSource_ls00.plDataToParamIndex_ls00[i]]->piBasicInfo_ls00;

        // <set_column_spec >    ::= SET <load_column_spec>
        // <load_column_spec>    ::= <column_descriptor> [ <null_condition>]
        // <column_descriptor>   ::= <valCOLUMN_NAME> <field_pos> <format_spec>
        // <null_condition  >    ::= NULL <if_option> <condition> | DEFAULT NULL
        pColumn = pMultColSpec->mcsColumn_ls00[pDatUpdRec->duprDataSource_ls00.plDataToColIndex_ls00[i]];

        // tls00_FieldFormat
        if ( pColumn->colFormat_ls00.ffoFrac_ls00 !=UNDEFINED_LS00 )
        {
            pColumn->colFormat_ls00.ffoFrac_ls00 = pFieldBasic->fbFraction_ls00;
        }

        // tls00_CondSpec
        if ( pColumn->colNullCond_ls00 )
        {
            rc = ls16ConvertCondition(*pColumn->colNullCond_ls00,
                                      pDBInfo->dbiOwnSwap_ls00,
                                      *pInFileFormat,
                                      errText);
            if (errOK_els00 != rc)
                return rc;
        }

        if (1 == szMap_LongDataType_ls00[pFieldBasic->fbDataType_ls00])
        {
            pColumn->colLongInfo.loiIsLong_ls00     = true;
            pColumn->colLongInfo.loiFileStruct_ls00 = new tls00_VFile;
            memset(pColumn->colLongInfo.loiFileStruct_ls00, 0, sizeof(tls00_VFile));

            // Check compatibility of external code type to db data type
            rc = ls08CheckLONG_DT_Compatibility(pColumn->colLongInfo.loiFileEncoding_ls00,
                                                pFieldBasic->fbDataType_ls00);
            if (errOK_els00 != rc)
            {
                // error: data types do not match (function returns only ok or errIncompatibleDataTypes_els98)
                pMsgObj->ls98Msg(layDataUpdate_els98, errText, errIncompatibleDataTypes_els98,
                                                               pColumn->colName_ls00.asCharp());
                break;
            }

         }  // end if (1 == szMap_LongDataType_ls00[pFieldBasic->fbDataType_ls00])

    }   // end for (tsp00_Int4 iColumn=0; iColumn < pTD->tdFieldCount_ls00; ++iColumn)


    //<longfile_spec_mlt> ::= [<longfile_spec>][<longfile_spec_mlt>]
    if (errOK_els00 == rc)
    {
       ls08InitLongFileInfo(pMultColSpec, &pTransformationCmd->trColLongSpec_ls00);
    }


    // <infile_spec>      ::= INFILE <valFILE_NAME> <file_format>
    if (errOK_els00 == rc)
    {
        tsp00_Int4 iBytesPerLine = ls18GetRowLength(pTransformationCmd->trColSpec_ls00,
                                                    *pTD,
                                                    //pInFileFormat->ffoBinary_ls00);
                                                    pInFileFormat->ffoFormatted_ls00);
        if (false == pInFileFormat->ffoBinary_ls00)
        {
            pInFileFormat->ffoBytesPerLine_ls00 = iBytesPerLine;
        }
        else
        {
            tls00_VFile vFile;
            ls30VFInitialize(vFile, pTransformationCmd->trDataFile_ls00.fsFileName_ls00);

            rc = ls30VFOpen(vFile,errText);
            if ( (errOK_els00 == rc) && (0 == pInFileFormat->ffoBytesPerLine_ls00) )
            {
                rc = ls30VFReadHeader(vFile, pInFileFormat->ffoBytesPerLine_ls00, errText);
                if( errNoDatafileHeader_ls98 == rc )
                {
                    pInFileFormat->ffoBytesPerLine_ls00= iBytesPerLine;
                    pMsgObj->ls98PrintMessage(layDataUpdate_els98, errNoDatafileHeader_ls98,
                                                                   pInFileFormat->ffoBytesPerLine_ls00);
                    rc = errOK_els00;
                }
                else
                {
                    rc = ls30VFClose(vFile, errText);
                }
            }
        }
    }   // end if (errOK_els00 == rc)

    return rc;
}
// ls29_InitDatUpdCmd()


/*-----------------------------------------------------------------------------
  ls29_FreeDatUpdCmd
/-----------------------------------------------------------------------------*/
void
ls29_FreeDatUpdCmd(tls00_TransformationCmd * pTransformationCmd)
{
    ROUTINE_DBG_MEO00 ("ls29_FreeDatUpdateCmd");

    tls00_MultColSpec *pMultColSpec = &pTransformationCmd->trColSpec_ls00;

    if (NULL != pMultColSpec)
    {
        char errText[255];
        errText[0] = 0;

        tls00_Column *pColumn = NULL;
        for (tsp00_Int4 iColumn = 0; iColumn < pMultColSpec->mcsCount_ls00 ; ++iColumn)
        {
            pColumn =  pMultColSpec->mcsColumn_ls00[iColumn];
            if ( true == pColumn->colLongInfo.loiIsLong_ls00)
            {
                ls30VFClose(*pColumn->colLongInfo.loiFileStruct_ls00, errText);

                if ( pColumn->colLongInfo.loiFileStruct_ls00 != NULL )
                {
                    delete pColumn->colLongInfo.loiFileStruct_ls00;
                    pColumn->colLongInfo.loiFileStruct_ls00   = NULL;
                }
                if( pColumn->colLongInfo.loiFileName_ls00 != NULL)
                {
                    delete [] pColumn->colLongInfo.loiFileName_ls00;
                    pColumn->colLongInfo.loiFileName_ls00     = NULL;
                }
            }
        }
    }
    // <infile_spec>
//    tls00_FileSpec    InFileSpec   = pTransformationCmd->trDataFile_ls00;
//    tls00_FileFormat  InFileFormat = InFileSpec.fsFormat_ls00;
}
// ls29_FreeDatUpdCmd()


/* -----------------------------------------------------------------------------
   ls29_GetRecFields
/------------------------------------------------------------------------------*/
static tsp00_Longint
ls29_GetRecFields(tls00_TransformationCmd   *pTransformationCmd,
                  tls00_DatUpdRec           *pDatUpdRec,
                  tsp1_sqlmode_Enum         SQLMode,
                  tsp00_Addr                errText)
{
    ROUTINE_DBG_MEO00 ("ls29_GetRecFields");

    LoaderMessages *pMsgObj = LoaderMessages::Instance();
    tsp00_Longint    rc = errOK_els00;

    tls00_TableDescription *pTD          = &pDatUpdRec->duprTableDescription_ls00;
    tls00_FileFormat       *pFileFormat  = &pTransformationCmd->trDataFile_ls00.fsFormat_ls00;
    tls00_MultColSpec      *pMultColSpec = &pTransformationCmd->trColSpec_ls00;
    tsp00_Addr              pInputLine   = STATIC_CAST(char*, pDatUpdRec->duprDataSource_ls00.dasInputBuffer.pBufPtr_ls00);
    tsp00_Int4              iInputLen    = pDatUpdRec->duprDataSource_ls00.dasInputBuffer.lBufPos_ls00;
    tls00_String           *pRecFields   = pDatUpdRec->duprDataSource_ls00.dasConvertedData;

    //*
    //*     Read data
    //*
    tsp00_Int4 lFailIndex = 0;
    if (true == pFileFormat->ffoFormatted_ls00)           // read formatted data
    {
        rc = ls18GetFormattedValueEx(pInputLine,
                                     iInputLen,
                                     &pTransformationCmd->trColSpec_ls00,
                                     pDatUpdRec->duprDataSource_ls00.lReadFieldsCnt_ls00,
                                     pDatUpdRec->duprDataSource_ls00.plDataToColIndex_ls00,
                                     pRecFields,
                                     lFailIndex);
    }
    else if (true == pFileFormat->ffoCompress_ls00)
    {
        rc = ls18GetCSVData(pInputLine,
                            iInputLen,
                            &pDatUpdRec->duprPattern_ls00,
                            pDatUpdRec->duprDataSource_ls00.lReadFieldsCnt_ls00,
                            pDatUpdRec->duprDataSource_ls00.lReadPos_ls00,
                            pTransformationCmd->trDataFile_ls00.fsFormat_ls00.ffoCodeType_ls00,
                            pRecFields,
                            lFailIndex);
    }

    if (errOK_els00 != rc)
    {
        pMsgObj->ls98Msg(layDataLoad_els98, errText, errAtRow_els98, pDatUpdRec->duprRecordCount_ls00);

        if (errMissingData_els98 == rc)
        {
            tsp00_Int4 lIndex = pDatUpdRec->duprDataSource_ls00.plDataToColIndex_ls00[lFailIndex];
            pMsgObj->ls98Msg(layDataLoad_els98, errText, errMissingData_els98,
                                                         pMultColSpec->mcsColumn_ls00[lIndex]->colName_ls00.asCharp() );
        }
    }

    tls00_ParamInfo   *pParamInfo  = NULL;
    tls00_Column      *pColumn     = NULL;

    // get fields of a record
    for (tsp00_Int4 i=0; ((errOK_els00 == rc) && (i < pTD->tdFieldCount_ls00) ); ++i)
    {
        pParamInfo  = pTD->tdParamArray_ls00[pDatUpdRec->duprDataSource_ls00.plDataToParamIndex_ls00[i]];

        // <set_column_spec>    ::= SET <load_column_spec>
        // <load_column_spec>   ::= <column_assignment> | [ <null_condition>] | <column_descriptor>

        // <key_column_spec>    ::= KEY <simple_column_spec>
        // <simple_column_spec> ::= <column_assignment> | <column_descriptor>
        pColumn = pMultColSpec->mcsColumn_ls00[pDatUpdRec->duprDataSource_ls00.plDataToColIndex_ls00[i]];

        rc = ls20TransformColumnValue(&pRecFields[i],
                                      pColumn,
                                      &pDatUpdRec->duprDataSource_ls00.dasInputBuffer,
                                      pParamInfo,
                                      &pTransformationCmd->trDataFile_ls00,
                                      pDatUpdRec->duprSwapKind_ls00,
                                      SQLMode,
                                      &pDatUpdRec->duprPattern_ls00,
                                      errText);
        if (errOK_els00 != rc)
        {
            pMsgObj->ls98PrintMessage(layDataUpdate_els98, errAtRow_els98, pDatUpdRec->duprRecordCount_ls00);
            pMsgObj->ls98EFromRcToFile(layDataUpdate_els98, errText, STATIC_CAST(ErrorNumbers, rc));
        }
    }   // end for (iColumn= 0 ; iColumn < pTD->tdFieldCount_ls00 ; ++iColumn)

    return rc;
}
// ls29_GetRecFields()
