/*
  -----------------------------------------------------------------------------
  module: vls20.cpp
  -----------------------------------------------------------------------------

  responsible:  SteffenS and d033893

  special area: SAP DB LOADER

  description:  Implementation of the DATALOAD functionality

  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 <time.h>

#include "gls00.h"
#include "hls01.h"
#include "hls03.h"
#include "hls04.h"
#include "hls041.h"
#include "hls05.h"
#include "hls07.h"
#include "hls08_long.h"
#include "hls10.h"
#include "hls11.h"
#include "hls13.h"
#include "hls15.h"
#include "hls16_condition.h"
#include "hls18.h"
#include "hls20.h"
#include "hls20_dataload.h"
#include "hls24.h"
#include "hls25.h"
#include "hls30.h"
#include "hls99.h"
#include "hls98msg.h"

/*!
  -----------------------------------------------------------------------------
  Chapter: Local functions
  -----------------------------------------------------------------------------
 */

/*!
  -----------------------------------------------------------------------------
  function:     ls20_InitDatLoadRec
  -----------------------------------------------------------------------------
  description:  initializes DATA load record structure

  arguments:    pDatLoadRec [IN] - structure with information on processing the
                                   dataload command
                pDBInfo     [IN] - structure with information on the running
                                   session and the database connected to.
  returnvalue:  No
  -----------------------------------------------------------------------------
*/
static tsp00_Int4
ls20_InitDatLoadRec( tls00_DBInfo      *pDBInfo,
                     tls00_TransformationCmd  *pTransformationCmd,
                     tls00_DloadRec   *&pDatLoadRec,
                     tsp00_Addr         ErrText );

/*
  -----------------------------------------------------------------------------
  function:     ls20_FreeDatLoadRec
  -----------------------------------------------------------------------------
  description:

  arguments:    pDatLoadRec  [IN] - structure with information on processing the
                                     dataload command
                pTransformationCmd [IN]  - structure with user information for
                                     processing dataload command.
  returnvalue:  No
  -----------------------------------------------------------------------------
*/
static void
ls20_FreeDatLoadRec(tls00_TransformationCmd* pTransformationCmd, tls00_DloadRec*& pDatLoadRec );

/*
  -----------------------------------------------------------------------------
  function:     ls20_InitStreams  - local function
  -----------------------------------------------------------------------------
  description:

  arguments:    pTransformationCmd  [IN]   - structure with information for te supplied by the user
              
  returnvalue:
  -----------------------------------------------------------------------------
*/
static tsp00_Int4
ls20_InitStreams(tls00_TransformationCmd* pTransformationCmd, tsp00_Addr pszErrText);

/*
  -----------------------------------------------------------------------------
  function:    ls20_InitAndOpenFiles
  -----------------------------------------------------------------------------
*/
static tsp00_Int4
ls20_InitAndOpenFiles(tls00_TransformationCmd *pTransformationCmd,
                      tls00_DloadRec  *&pDatLoadRec,
                      tsp00_Addr        pszErrText);

/*!
  -----------------------------------------------------------------------------
  function:     ls20_ParseInsertStmt
  -----------------------------------------------------------------------------
  description:  Prepare INSERT Statement as mass command.
                Extraxt table information out of the answer packet

  arguments:    DBInfo      [IN]    - structure with info on running session and
                                       database connected to
                pTransformationCmd    [IN]    - structure with user information for
                                       processing dataload command
                pDatLoadRec    [IN]    - structure with information on
                                       processing the dataload command
                ErrText     [OUT]   - error text

  returnvalue:  errOK_els00         - in case of NO errors
                some other errors   - in case of errors
  -----------------------------------------------------------------------------
*/
static tsp00_Int4
ls20_ParseInsertStmt(tls00_DBInfo     *pDBInfo,
                     tls00_TransformationCmd *pTransformationCmd,
                     tls00_DloadRec   *pDatLoadRec,
                     tsp00_Addr        pszErrText);

/*!
  -----------------------------------------------------------------------------
  function:     ls20_ValueToOIBuffer
  -----------------------------------------------------------------------------

  description:  Writes single DATA to DATA part buffer in the right format.
                Data has be given in the right database format.
   
  arguments:    pInputData          [IN]     - Data to write to buffer
                ParameterInfo       [IN]     - Info describing DATA
                pColumn             [IN]     - Structure describing column
                DataFileEncoding    [IN]     - Data file encoding
                bUnicodeOI          [IN]     - Database UNICODE or ASCII
                pOIValueBuffer      [IN/OUT] - Buffer to put the DATA in
                pszErrText          [OUT]    - Error text
  
  returnvalue:  errOK_els00                 - No error
                errIncompatibleConst_els98  - Error inserting assigned value
                errUnknownAssignment_els98  - Error inserting assigned value
                errInternal_els98           - Error converting between encodings
                errConvertingEncoding_els98 - Error converting between encodings
  -----------------------------------------------------------------------------
*/
tsp00_Int4
ls20_ValueToOIBuffer(tls00_String        &pInputData,
                     tls00_ParamInfo     &ParameterInfo,
                     tls00_Column        *pColumn,
                     tls00_CodeType       DataFileEncoding,
                     tsp81_CodePage      *pCodePageTable,
                     bool                 bUnicodeOI,
                     unsigned char       *pOIValueBuffer,
                     tsp00_Addr           pszErrText);
/*
  -----------------------------------------------------------------------------
  function:     ls20_CheckHeader
  -----------------------------------------------------------------------------
*/
static tsp00_Int4
ls20_CheckHeader(tls00_DBInfo            *pDBInfo,
                 tls00_TransformationCmd *pDatLoadCmd,
                 Tools_DynamicUTF8String  DatExtrStmt,
                 tsp00_Addr               ErrText);
/*
  -----------------------------------------------------------------------------
  function:     ls20_InitStructures
  -----------------------------------------------------------------------------
*/
static tsp00_Int4
ls20_InitStructures(tls00_DBInfo     *pDBInfo,
                    tls00_TransformationCmd *pTransformationCmd,
                    tls00_DloadRec   *pDatLoadRec,
                    tsp00_Addr        pszErrText);

/*!
  -----------------------------------------------------------------------------
  function:     ls20_LoadRowColumns
  -----------------------------------------------------------------------------
  description:  Loop for building mass insert requests, sending them to the kernel
                checking the kernel answer, sending putvals, ...


  arguments:    DBInfo      [IN]    - structure with info on running session and
                                       database connected to
                pTransformationCmd [IN]    - structure with user information for
                                       processing dataload command
                pDatLoadRec [IN]    - structure with information on
                                       processing the dataload command
                ErrText     [OUT]   - error text

  returnvalue:  errOK_els00         - in case of NO errors
                some other errors   - in case of errors
  -----------------------------------------------------------------------------
*/
static tsp00_Int4
ls20_LoadRowColumns(tls00_DBInfo     *DBInfo,
                   MetaDataDef  *&pMetaDataDef,
                   tls00_TransformationCmd *pTransformationCmd,
                   tls00_DloadRec   *pDatLoadRec,
                   tls00_String     &pOI_InitBlock,
                   tsp00_Addr        ErrText);

/*!
  -----------------------------------------------------------------------------
  function:     ls20_TransformRowColumns
  -----------------------------------------------------------------------------
  description:  Build a database record

                This function builds one database record and writes it to a buffer.

  arguments:    pTransformationCmd    [IN]    - structure with user information for
                                       processing dataload command.
                pDatLoadRec    [IN]    - structure with information on
                                       processing the dataload command
                Errtext     [OUT]   - error text

  returnvalue:  errOK_els00         - in case of NO errors
                some other errors   - in case of errors
  -----------------------------------------------------------------------------
*/
static tsp00_Int4
ls20_TransformRowColumns(tls00_TransformationCmd  *pTransformationCmd,
                         tls00_DloadRec     *pDatLoadRec,
                         tsp1_sqlmode_Enum  SQLMode,
                         bool               bUnicodeOI,
                         tsp00_Addr         ErrText);

/*!
  -----------------------------------------------------------------------------
  function:     ls20_TransformTableRows
  -----------------------------------------------------------------------------
  description:  Build as many database records as fit into one packet

                This function builds one database record and writes it to a buffer.

  arguments:    DBInfo      [IN]    - structure with info on running session and
                                       database connected to
                pTransformationCmd [IN]    - structure with user information for
                                       processing dataload command
                pDatLoadRec [IN]    - structure with information on
                                       processing the dataload command
                ErrText     [OUT]   - error text
                RowCount    [OUT]   - Count of records stored in pszRecord
                bPutVal     [OUT]   - flags the need of using putval - oi-packets
                                       to process remaining long values

  returnvalue:  errOK_els00         - in case of NO errors
                error reading file
                error in processing DATA uebersteigt maxerrorcount
                  some other errors - in case of errors
  -----------------------------------------------------------------------------
*/
static tsp00_Int4
ls20_TransformTableRows(tls00_DBInfo     *DBInfo,
                        tls00_TransformationCmd *pTransformationCmd,
                        tls00_DloadRec   *pDatLoadRec,
                        bool              bRecoverLong,
                        tsp00_Addr        ErrText,
                        tsp00_Int4       &RowCount,
                        bool             &bPutVal);

/*
  -----------------------------------------------------------------------------
  function:     ls20_InitAndOpenLongFiles
  -----------------------------------------------------------------------------

  description:  Initializes VFile structures for long files and opens them.

  arguments:    pMultCol        [IN]  - User delivered DATA on output columns;
                                         stores the long DATA file struct, too
                ErrText         [OUT] - Error text

  returnvalue:  errOK_els00        - Success
                errFileOpen_els98  - error opening file
  -----------------------------------------------------------------------------
*/
static tsp00_Int4
ls20_InitAndOpenLongFiles(tls00_MultColSpec  *pMultCol,
                          tsp00_Addr          ErrText);

/*!
  -----------------------------------------------------------------------------
  EndChapter:   Local function declaration
  -----------------------------------------------------------------------------
 */

/*
  -----------------------------------------------------------------------------
  BeginChapter: Global function implementation
  -----------------------------------------------------------------------------
*/

/*
  -----------------------------------------------------------------------------
  function:     ls20LoadTableColumns
  -----------------------------------------------------------------------------
*/
tsp00_Int4
ls20LoadTableColumns(MetaDataDef     *&pMetaDataDef,
                     tls00_DloadRec  *pDatLoadRec,
                     tsp00_Addr      ErrText)
{
    ROUTINE_DBG_MEO00 ("ls20LoadTableColumns");

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

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

    tls00_LargeNumber start_Data;
    start_Data.lnu2GB_Blocks_ls00 = 0;
    start_Data.lnuRemainder_ls00  = 0;

    start_Data.lnu2GB_Blocks_ls00 = pDatLoadRec->dlrInfile_ls00->vfFilePos_ls00.lnu2GB_Blocks_ls00;
    start_Data.lnuRemainder_ls00  = pDatLoadRec->dlrInfile_ls00->vfFilePos_ls00.lnuRemainder_ls00;
    //*
    //*  create dataload record structure
    //*
    rc = ls20_InitDatLoadRec(pDBInfo, pTransformationCmd, pDatLoadRec, ErrText);

    //*
    //*  update transformation table and read metadata header
    //*
    if ( errOK_els00 == rc )
    {
         rc = ls20UpdateTransformationPackage(pDBInfo,pMetaDataDef,pTransformationCmd,pDatLoadRec,ErrText);

         if (errOK_els00 != rc )
         {
             pMsgObj->ls98Msg(layDataExtract_els98, ErrText, errInternal_els98, __FILE__, __LINE__, rc );
             return errInternal_els98;
         }
         rc = ls15RSCommit(pDBInfo, ErrText);

         if (true  == pTransformationCmd->trDataFile_ls00.fsFormat_ls00.ffoCompact_ls00)
             rc = ls20ReadMetaHeader(pDBInfo,*pDatLoadRec->dlrInfile_ls00, pTransformationCmd, pDatLoadRec, ErrText );
    }
    //*
    //*   load DATA record values
    //*
    tsp00_Longint lRejectedRows = pDatLoadRec->dlrLRejected_ls00;

    if ( errOK_els00 == rc &&
         false == pDatLoadRec->dlrTabEmpty_ls00 &&
         false == pTransformationCmd->trExclude_ls00   )
    {
        if (ctUnknown_els00 != pTransformationCmd->trDataFile_ls00.fsFormat_ls00.ffoCodeType_ls00)
        {
            rc = ls05AreEncodingsCompatible(pTransformationCmd->trDataFile_ls00.fsFormat_ls00.ffoCodeType_ls00,
                                            ls00IsDBUnicode(pDBInfo) ? ctUCS2_els00 : ctAscii_els00);
            if (errOK_els00 != rc)
            {
                // Unicode file and ascii DB do not match
                pMsgObj->ls98Msg(layDataLoad_els98, ErrText, errIncompatibleEncodings_els98);
                rc = errIncompatibleEncodings_els98;
            }
        }

        //*
        //*  run dataload
        //*
        if (errOK_els00 == rc)
        {
            rc = ls20_InitStructures(pDBInfo, pTransformationCmd, pDatLoadRec, ErrText);
        }
        //*
        //*  initialize packet used sending DATA to the kernel
        //*
        tls00_Buffer *pDataBuffer       = &pDatLoadRec->dlrDataPartHandling_ls00.dphBuffer_ls00;
        tls00_String pOIPacketInitBlock;
        pOIPacketInitBlock.strLeng_ls00 = 0;
        pOIPacketInitBlock.strAddr_ls00 = NULL;

        if (errOK_els00 == rc)
        {
            pOIPacketInitBlock.strLeng_ls00 = BlockHSize_ls00 + PartHSize_ls00 + PartHSize_ls00 + 256;
            pOIPacketInitBlock.strAddr_ls00 = new char[pOIPacketInitBlock.strLeng_ls00];

            rc = ls20InitializeOIPacket(pDBInfo,
                                        pDatLoadRec->dlrParseId_ls00,
                                        pDatLoadRec->dlrResultCount_ls00,
                                        pDatLoadRec->dlrPartAttr_ls00,
                                        pOIPacketInitBlock,
                                        pDataBuffer);
        }

        // Here starts the REAL dataload only
        // To indicate errors before dataloading we use a 'hack' - set rejected to 1 to prevent from
        // continuing if max admissible errors is 1
//TODOTODO separate preparation and real load to give the caller the opportunity to handle
//         the return codes respectively
        if (errOK_els00 != rc)
        {
            pDatLoadRec->dlrLRejected_ls00 = 1;
        }

        //*
        //*  run dataload
        //*
        if (errOK_els00 == rc)
        {
            rc = ls20_LoadRowColumns(pDBInfo,pMetaDataDef, pTransformationCmd, pDatLoadRec, pOIPacketInitBlock, ErrText);

            if (errOK_els00 == rc)
            {
                if ( 0 == pDatLoadRec->dlrRecordCount_ls00 && ptTable_els00 == pDatLoadRec->dlrPartSpec_ls00.psPartType_ls00 )
                {
                    pMsgObj->ls98Msg(layDataLoad_els98, ErrText, msgEmptyDataFile_els98, pDatLoadRec->dlrInfile_ls00->vfFileName_ls00);
                    rc = msgEmptyDataFile_els98;
                }
            }
        }
        //*
        //* some cleaning work
        //*
        if (NULL != pOIPacketInitBlock.strAddr_ls00)
        {
            delete [] pOIPacketInitBlock.strAddr_ls00;
            pOIPacketInitBlock.strAddr_ls00 = NULL;
        }
        //*
        //* write log file
        //*
        if ( (errOK_els00 == rc) && (false  == pTransformationCmd->trInternal_ls00) )
        {
            char* _ptmp = pTransformationCmd->trTable_ls00.tsTabOwnr_ls00.asCharp();
            if (0 == pTransformationCmd->trTable_ls00.tsTabOwnr_ls00.length())
            {
                _ptmp =pDBInfo->dbiSession_ls00.siUserName_ls00.asCharp();
            }
            if (false         == pTransformationCmd->trDataFile_ls00.fsFormat_ls00.ffoCompact_ls00 && 
                ptTable_els00  < pTransformationCmd->trPartSpec_ls00.psPartType_ls00 )
            {
                pMsgObj->ls98PrintMessage(layDataLoad_els98,msgDLSuccessful_els98, _ptmp,
                                          pTransformationCmd->trTable_ls00.tsTabName_ls00.asCharp());
            }
            else if ( ptTable_els00  < pTransformationCmd->trPartSpec_ls00.psPartType_ls00 )
            {
                pMsgObj->ls98PrintMessage(layDataLoad_els98,msgTL0Successful_els98,_ptmp, 
                                          pTransformationCmd->trTable_ls00.tsTabName_ls00.asCharp() );
            }
        }

        if (rc != errFileOpen_els98)
        {
            // adapt dlrLastCommLine_ls00 for the case of a defined start position
            if (UNDEFINED_LS00 != pTransformationCmd->trDataFile_ls00.fsExtract_ls00.feStart_ls00.lnuRemainder_ls00)
            {
                // problems with all|user ?
                pDatLoadRec->dlrLastCommLine_ls00 += pTransformationCmd->trDataFile_ls00.fsExtract_ls00.feStart_ls00.lnuRemainder_ls00;
            }

            if ( false == pTransformationCmd->trInternal_ls00 )
            {
                if ( true  == pDBInfo->dbiSession_ls00.siAutoCommit_ls00 )
                     pMsgObj->ls98PrintMessage(layDataLoad_els98, msgLastCommInputLine_els98,
                                                                  pDatLoadRec->dlrLastCommLine_ls00);
                else
                    pMsgObj->ls98PrintMessage(layDataLoad_els98, msgLastInsInputLine_els98,
                                                                 pDatLoadRec->dlrLastCommLine_ls00);

                pMsgObj->ls98PrintMessage(layDataLoad_els98, msgInsertedRejectedRows_els98,
                                                             pDatLoadRec->dlrInsertedRows_ls00,
                                                             pDatLoadRec->dlrLRejected_ls00);

            }//if ( false == pTransformationCmd->trInternal_ls00 )

        }
    } //false == pDatLoadRec->dlrTabEmpty_ls00

    //*
    //*  update transformation table and read metadata trailer
    //*
    if ( errOK_els00 == rc  )
    {
         if  (true == pTransformationCmd->trDataFile_ls00.fsFormat_ls00.ffoCompact_ls00)
         {
            Tools_DynamicUTF8String  DatLoadStmt;

            rc = ls20ReadMetaTrailer(pDBInfo, pTransformationDef, *pDatLoadRec->dlrInfile_ls00, pTransformationCmd, pDatLoadRec, DatLoadStmt, ErrText);

            if (errOK_els00 != rc )
            {
                pMsgObj->ls98Msg(layDataLoad_els98, ErrText, errInternal_els98, __FILE__, __LINE__, rc );
                rc = errInternal_els98;
            }
         }
         if (errOK_els00 == rc)
         {
             rc = ls20UpdateTransformationPackage(pDBInfo,pMetaDataDef,pTransformationCmd,pDatLoadRec,ErrText);
             if (errOK_els00 == rc )
             {
                 rc = ls15RSCommit(pDBInfo, ErrText);
                 if( true == pDatLoadRec->dlrTabEmpty_ls00 && false == pTransformationCmd->trInternal_ls00  )
                      pMsgObj->ls98PrintMessage(layDataLoad_els98, msgInsertedRejectedRows_els98,
                                                                   pDatLoadRec->dlrInsertedRows_ls00,
                                                                   pDatLoadRec->dlrLRejected_ls00);
             }
             else
             {
                 pMsgObj->ls98Msg(layDataLoad_els98, ErrText, errInternal_els98, __FILE__, __LINE__, rc );
                 rc = errInternal_els98;
             }
         }
    }

    // Check if any record of a this single table could be inserted
    if ( (errOK_els00 == rc)                      &&
         (false == pDatLoadRec->dlrTabEmpty_ls00) &&
         (pDatLoadRec->dlrRecordCount_ls00 == (pDatLoadRec->dlrLRejected_ls00 - lRejectedRows) ) )
    {
        pMsgObj->ls98Msg(layDataLoad_els98, ErrText, errDLNoDataLoaded_els98,
                                                     pTransformationCmd->trTable_ls00.tsTabName_ls00.asCharp());
        rc = errDLNoDataLoaded_els98;
    }

    // Write some status message to the return string in any case - error or not
    if ( false == pTransformationCmd->trInternal_ls00 )
    {
        pMsgObj->ls98AppendStatusToString(layDataLoad_els98, ErrText, statInsertedRejectedRows_els98,
                                                                      STATIC_CAST(SAPDB_Int8, pDatLoadRec->dlrInsertedRows_ls00),
                                                                      STATIC_CAST(SAPDB_Int8, pDatLoadRec->dlrLRejected_ls00));
    }


    //*
    //*   free dataload record structure
    //*
    ls20_FreeDatLoadRec(pTransformationCmd, pDatLoadRec);

    tls00_LargeNumber end_Data;
    end_Data.lnu2GB_Blocks_ls00 = 0;
    end_Data.lnuRemainder_ls00  = 0;

    end_Data.lnu2GB_Blocks_ls00 = pDatLoadRec->dlrInfile_ls00->vfFilePos_ls00.lnu2GB_Blocks_ls00;
    end_Data.lnuRemainder_ls00  = pDatLoadRec->dlrInfile_ls00->vfFilePos_ls00.lnuRemainder_ls00;

    return rc;
}
// ls20LoadTableColumns()

/*
  -----------------------------------------------------------------------------
  function:     ls20ReadMetaHeader
  -----------------------------------------------------------------------------
*/
// Fills/compares code type of data file
tsp00_Int4
ls20ReadMetaHeader( tls00_DBInfo            *pDBInfo,
                    tls00_VFile              &VFile,
                    tls00_TransformationCmd  *pDatLoadCmd,
                    tls00_DloadRec           *pDatLoadRec,
                    tsp00_Addr               ErrText)
{
    ROUTINE_DBG_MEO00 ("ls20ReadMetaHeader");

    tsp00_Int4 rc = errOK_els00;

    assert(VFile.vfDataType_ls00 == sp5vf_binary);  // opened in binary mode?

    tls30_FileMetaDataHeader   FileMetaDataHeader;
    tls00_MetaData            *pMeta              = &pDatLoadRec->dlrMetaData_ls00;
    tsp00_SwapKind_Enum       *pSSwap             = &pMeta->mdSwapKind_ls00;
    tsp00_Uint4              *&pLongPos           = pMeta->pmdLongFieldPos_ls00;
    Tools_DynamicUTF8String    DatExtrStmt;

    // First read length of buffer from file
    tsp00_Versionc Version;
    tsp00_Longint rlen = 0;

    tsp00_Int4 buflen = Version.size() + sizeof(char) + sizeof(tsp00_Int4);

    tsp00_Addr pszBuffer = new _TCHAR[buflen];
    memset(pszBuffer, 0, buflen);
    tsp00_Addr pszKeepBufPtr = pszBuffer;

    rlen = ls30VFReadLnEx(VFile, pszBuffer, ErrText, buflen);
    if (rlen <= 0)         // In case of error length corresponds to error number
        rc = STATIC_CAST(tsp00_Int4, rlen);
    else
    {
        bool bCP_Avail = false;     // The version defines if we can expect a code page mapping table
                                    // for mapping ASCII to UCS2
        // Read version info
        SAPDB_memcpy(REINTERPRET_CAST(char*, &Version), pszBuffer, Version.size());
        pszBuffer += Version.size();

        // Check version
        if ( ('7' == Version[sizeof(tsp100_CompName)]) &&
             (Version[sizeof(tsp100_CompName) + 2]) >= '4' )
            bCP_Avail = true;

        tsp00_SwapKind_Enum DSwap = SERVER_SWAPPING_LS00;

        *pSSwap = STATIC_CAST(tsp00_SwapKind_Enum, *pszBuffer);

        TRACE_PRNF_MLS99(("ls20ReadMetaHeader", "SSwap = %d \n", *pSSwap) );

        pszBuffer += sizeof(unsigned char);

        // Define header length for buffer to read; we have to take into account the fact
        // that the header is aligned to full kB written -> so we need to read at least
        // the full kB
        tsp00_Int4 hlen = 0;
        SAPDB_memcpy(&hlen, pszBuffer, sizeof(hlen));

        hlen = ls07Swap4BInt(hlen, *pSSwap, DSwap);

        hlen -= buflen;             // header length contains the length of preheader info, too

        assert ( hlen > 0 );

        tsp00_Addr pszHeader = new _TCHAR[hlen];
        memset(pszHeader, 0, hlen);
        tsp00_Addr pszKeepHeaderPtr = pszHeader;

        rlen = ls30VFReadLnEx(VFile, pszHeader, ErrText, hlen);
        if (rlen <= 0)  // EOF_LS00 = -1
        {
            rc = STATIC_CAST(tsp00_Int4, rlen);
            return rc;
        }
        else
        {
            if (true == bCP_Avail)
            {
                //*
                //*     We can expect a code page (at least)
                //*

                // First read the code type before reading the code page
                tls00_CodeType CodeType = STATIC_CAST(tls00_CodeType, *pszHeader);
                pszHeader += sizeof(char);

                if (ctUnknown_els00 == pDatLoadCmd->trDataFile_ls00.fsFormat_ls00.ffoCodeType_ls00)
                {
                    if (ctUCS2Native_els00 == CodeType)
                    {
                        if (sw_full_swapped == *pSSwap)
                        {
                            pDatLoadCmd->trDataFile_ls00.fsFormat_ls00.ffoCodeType_ls00 = ctUCS2Swapped_els00;
                        }
                        else
                        {
                            pDatLoadCmd->trDataFile_ls00.fsFormat_ls00.ffoCodeType_ls00 = ctUCS2_els00;
                        }
                    }
                    else
                    {
                        pDatLoadCmd->trDataFile_ls00.fsFormat_ls00.ffoCodeType_ls00 = CodeType;
                    }
                }


                // Check if default code page was used upon extract (= ISO-8859-1)
                bool bDefaultCPUsed = (0 != *pszHeader);
                pszHeader += sizeof(char);

                // Now read the code page information
                tsp81_CodePage *pCP = pDatLoadRec->dlrDataSource_ls00.pdasCodePage_ls00;


                // There will be a code page name and a mapping table only in case the
                // code type of the file is ASCII and the code page is not ISO-8859-1
                if (ctAscii_els00 == CodeType)
                {
                    if (false == bDefaultCPUsed)
                    {
                        // Default code page was NOT used; so there should be code page
                        // information be found

                        // Code page name
                        pCP->name.Init();
                        pCP->name.rawAssign(pszHeader);
                        pszHeader += sizeof(tsp00_KnlIdentifierc);

                        // Code page UCS2 mapping
                        SAPDB_memcpy(pCP->map, pszHeader, sizeof(pCP->map));

                        if (*pSSwap != DSwap)
                            ls07SwapUCS2StringInPlace(REINTERPRET_CAST(char*, pCP->map), MAX_UINT1_SP00 + 1);

                        // Try to ensure there is really some code page mapping
                        if ( (0 == pCP->map[0]) && (1 == pCP->map[1]) )
                            pszHeader += sizeof(pCP->map);
                    }
                    else
                    {
                        // Default code page was used upon extract; we must make sure that our
                        // code page struct that's used for loading contains the default code
                        // page
                        pCP->name.Init();
                        pCP->name.rawAssign(pszDefaultCodePageName_ls00);

                        SAPDB_memcpy(pCP->map, lDefaultCodePageMap_ls00, 256*sizeof(tsp00_Uint2));
                    }
                }
            }

            SAPDB_memcpy(&FileMetaDataHeader.mdRecordLength_ls30, pszHeader, sizeof(FileMetaDataHeader.mdRecordLength_ls30));
            FileMetaDataHeader.mdRecordLength_ls30 = ls07Swap4BInt(FileMetaDataHeader.mdRecordLength_ls30, *pSSwap, DSwap);
            pszHeader += sizeof(tsp00_Uint4);

            SAPDB_memcpy(&FileMetaDataHeader.mdFieldCount_ls30, pszHeader, sizeof(FileMetaDataHeader.mdFieldCount_ls30));
            FileMetaDataHeader.mdFieldCount_ls30 = ls07Swap4BInt(FileMetaDataHeader.mdFieldCount_ls30, *pSSwap, DSwap);
            pszHeader += sizeof(tsp00_Uint4);

            SAPDB_memcpy(&FileMetaDataHeader.mdLongCount_ls30, pszHeader, sizeof(FileMetaDataHeader.mdLongCount_ls30));
            FileMetaDataHeader.mdLongCount_ls30 = ls07Swap4BInt(FileMetaDataHeader.mdLongCount_ls30, *pSSwap, DSwap);
            pszHeader += sizeof(tsp00_Uint4);

            SAPDB_memcpy(&FileMetaDataHeader.mdMetaData_ls30, pszHeader, sizeof(tls00_FileFormat));
            pszHeader += sizeof(tls00_FileFormat);

            SAPDB_memcpy(&FileMetaDataHeader.mdTableEmpty_ls30, pszHeader, sizeof(FileMetaDataHeader.mdTableEmpty_ls30));
            FileMetaDataHeader.mdTableEmpty_ls30 = ls07Swap4BInt(FileMetaDataHeader.mdTableEmpty_ls30, *pSSwap, DSwap);
            pszHeader += sizeof(tsp00_Uint4);

            if ( 0    != FileMetaDataHeader.mdLongCount_ls30       )
            {
                // read long positions from DATA record behind read header
                pLongPos = new tsp00_Uint4[FileMetaDataHeader.mdLongCount_ls30];

                for (tsp00_Uint4 i = 0; i < FileMetaDataHeader.mdLongCount_ls30; ++i)
                {
                    SAPDB_memcpy(&pLongPos[i], pszHeader, sizeof(pLongPos[i]));
                    pLongPos[i] = ls07Swap4BInt(pLongPos[i], *pSSwap, DSwap);
                    pszHeader += sizeof(tsp00_Uint4);
                }
            }

            // read command from buffer
            DatExtrStmt.Assign(REINTERPRET_CAST(Tools_DynamicUTF8String::ConstPointer, pszHeader));

            if (NULL != pszKeepHeaderPtr)
            {
                delete [] pszKeepHeaderPtr;
                pszKeepHeaderPtr = NULL;
                pszHeader        = NULL;
            }
        }

        if (pszKeepBufPtr != NULL)
        {
            delete [] pszKeepBufPtr;
            pszKeepBufPtr = NULL;
            pszBuffer     = NULL;
        }
    }

    // parse   owner, tablename from command string in   DATA    file header
    // compare owner, tablename to   command string from CATALOG table
    rc = ls20_CheckHeader(pDBInfo, pDatLoadCmd, DatExtrStmt, ErrText);
    if (errOK_els00 == rc)
    {
        pMeta->mdFieldCount_ls00     = FileMetaDataHeader.mdFieldCount_ls30;
        pMeta->mdLongFieldCount_ls00 = FileMetaDataHeader.mdLongCount_ls30;

        pMeta->mdLengthArrayLen_ls00 = pMeta->mdFieldCount_ls00 + pMeta->mdLongFieldCount_ls00;
        pMeta->pmdLengthArray_ls00   = new tsp00_Int2[pMeta->mdLengthArrayLen_ls00];
        memset(pMeta->pmdLengthArray_ls00, 0, (sizeof(tsp00_Int2) * pMeta->mdLengthArrayLen_ls00));
        pMeta->pmdMetaFile_ls00      = pDatLoadRec->dlrInfile_ls00;

        FileMetaDataHeader.mdTableEmpty_ls30  == 1 ? pDatLoadRec->dlrTabEmpty_ls00 = true :
                                                     pDatLoadRec->dlrTabEmpty_ls00 = false;

        if ( true == pDatLoadCmd->trExclude_ls00 )
             pDatLoadRec->dlrNumTabExcludedExtr_ls00++;
    }
    else
        ;//!!ErrorHandling

    return rc;
}
//  ls20ReadMetaHeader()

/*
  -----------------------------------------------------------------------------
  function:     ls20ReadMetaTrailer
  -----------------------------------------------------------------------------
*/
tsp00_Int4
ls20ReadMetaTrailer( tls00_DBInfo           *pDBInfo,
                     TransformationDef      *&pTransformationDef,
                     tls00_VFile             &VFile,
                     tls00_TransformationCmd *pTransformationCmd,
                     tls00_DloadRec          *pDatLoadRec,
                     Tools_DynamicUTF8String &DatLoadStmt,
                     tsp00_Addr               ErrText )
{
    ROUTINE_DBG_MEO00 ("ls20ReadMetaTrailer");

    tsp00_Int4 rc = errOK_els00;

    // opened in binary mode
    assert(VFile.vfDataType_ls00 == sp5vf_binary);

    // read table end marker
    tsp00_Longint rlen    = 0;
    tsp00_Int4    buflen  = pDatLoadRec->dlrMetaData_ls00.mdLongFieldCount_ls00 * sizeof(tsp00_Int4) +
                           (pDatLoadRec->dlrMetaData_ls00.mdFieldCount_ls00 -
                            pDatLoadRec->dlrMetaData_ls00.mdLongFieldCount_ls00)* sizeof(tsp00_Int2);

    if ( (true == pDatLoadRec->dlrTabEmpty_ls00) || (true == pTransformationCmd->trExclude_ls00) )
    {
         tsp00_Addr pszNoMoreData;
         pszNoMoreData = new _TCHAR[buflen];
         memset(pszNoMoreData, 0, buflen);
         rlen = ls30VFReadLnEx(VFile, pszNoMoreData, ErrText, buflen);
         if ( pszNoMoreData != NULL )
         {
             delete [] pszNoMoreData;
             pszNoMoreData = NULL;
         }
    }

    // trailer length table end | command | alignment
    tsp00_Int4 trailerlen = sizeof(tsp00_Int4);
    tsp00_Int4 hlen       = 0;

    rlen = ls30VFReadLnEx(VFile, REINTERPRET_CAST(char*, &hlen), ErrText, trailerlen);
    if (rlen <= 0)
    {
        rc = STATIC_CAST(tsp00_Int4, rlen);
    }

    hlen  = ls07Swap4BInt(hlen, pDatLoadRec->dlrMetaData_ls00.mdSwapKind_ls00, pDatLoadRec->dlrSwapKind_ls00);
    hlen -= trailerlen;
    hlen -= buflen;

    assert ( hlen > 0 );

    tsp00_Addr pszTrailer;
    pszTrailer = new _TCHAR[hlen];
    memset(pszTrailer, 0, hlen);

    // <TRAILER_BLOCK>:<TRAILER_POS>
    //pTransformationDef->m_trailerpos.lnu2GB_Blocks_ls00= VFile.vfFilePos_ls00.lnu2GB_Blocks_ls00;
    //pTransformationDef->m_trailerpos.lnuRemainder_ls00 = VFile.vfFilePos_ls00.lnuRemainder_ls00;

    rlen = ls30VFReadLnEx(VFile, pszTrailer, ErrText, hlen);
    if (rlen <= 0)
        rc = STATIC_CAST(tsp00_Int4, rlen);

    // transformation statement
    DatLoadStmt.AssignRaw( REINTERPRET_CAST(unsigned char*,pszTrailer), _tcslen(pszTrailer) );

    if (NULL != pszTrailer)
    {
        delete [] pszTrailer;
        pszTrailer = NULL;
    }

    return rc;
}
// ls20ReadMetaTrailer()

/*
  -----------------------------------------------------------------------------
  function:     ls20InitDataSourceStruct
  -----------------------------------------------------------------------------
*/
void
ls20InitDataSourceStruct(tls00_DataSource  *pDataSource,
                         tls00_FileFormat  *pFileFormat,
                         tsp00_Int4         lFieldCount,        // tabledescription->fieldcount_ls00
                         tls00_MultColSpec *pMultColSpec,
                         tsp00_Int4         lSetColumnIndex)    // applies only to DATAUPDATE command; defaults to 0
{
    ROUTINE_DBG_MEO00 ("ls20InitDataSourceStruct");

    tls00_Column *pCol = NULL;

    pDataSource->dasCodeType_ls00 = pFileFormat->ffoCodeType_ls00;

    pDataSource->dasInputBuffer.pBufPtr_ls00 = new char[pDataSource->dasInputBuffer.lBufLen_ls00];
    pDataSource->dasInputBuffer.lBufPos_ls00 = 0;

    ls18RecordConstructor(lFieldCount, pDataSource->dasConvertedData);

    pDataSource->lReadFieldsCnt_ls00 = lFieldCount;

    // We need only as much read positions as we have DATA fields to read
    pDataSource->lReadPos_ls00           = new tsp00_Uint4[lFieldCount];
    pDataSource->plDataToColIndex_ls00   = new tsp00_Uint4[lFieldCount];
    pDataSource->plDataToParamIndex_ls00 = new tsp00_Uint4[lFieldCount];

    tsp00_Int4 lSetColCount = lFieldCount - lSetColumnIndex;

    for (int j = 0, k=0; j < pMultColSpec->mcsCount_ls00; ++j)
    {
        pCol = pMultColSpec->mcsColumn_ls00[j];
        if (asUnknown_els00 == pCol->colAssign_ls00.fasAsgnTyp_ls00)
        {
            pDataSource->plDataToColIndex_ls00[k] = j;

            pDataSource->lReadPos_ls00[k] = (0 == pCol->colFPos_ls00.fpoStart_ls00) ?
                                            j + 1 :
                                            pCol->colFPos_ls00.fpoStart_ls00;
            if (0 != lSetColumnIndex)
            {
                if (k < lSetColumnIndex)
                {
                    pDataSource->plDataToParamIndex_ls00[k] = k + lSetColCount;
                }
                else
                {
                    pDataSource->plDataToParamIndex_ls00[k] = k - lSetColumnIndex;
                }
            }
            else
            {
                pDataSource->plDataToParamIndex_ls00[k] = k;
            }
            ++k;
        }   // end if (asUnknown_els00 == pCol->colAssign_ls00.fasAsgnTyp_ls00)
    }   // end for (int j = 0, k=0; j < pMultColSpec->mcsCount_ls00; ++j)

    return;
}
// ls20InitDataSourceStruct()

/*
  -----------------------------------------------------------------------------
  function:     ls20InitializeOIPacket
  -----------------------------------------------------------------------------
*/
tsp00_Int4
ls20InitializeOIPacket(tls00_DBInfo         *pDBInfo,
                       char                 *pszParseID,
                       unsigned char        *pszResultCount,
                       tsp1_part_attributes  PartAttribute,
                       tls00_String         &pOIPacketInitBlock,
                       tls00_Buffer         *pDataPartBuffer)
{
    ROUTINE_DBG_MEO00 ("ls20InitializeOIPacket");

    tsp00_Int4 rc = errOK_els00;

    tsp1_packet  *pSqlPacket = pDBInfo->dbiPktSndList_ls00[0];
    tsp1_segment *pSqlSegm   = NULL;
    tsp1_part    *pSqlPart   = NULL;

    //*
    //*     Generate Execute Command
    //*
    //* 1.part: parse id
    //* 2.part: daten
    //* 3.part: result count
    //*
    rc = ls04FastInit(pSqlPacket, &pSqlSegm, &pSqlPart, pDBInfo);
    ls04SetMsgType(pSqlSegm, sp1m_execute);                      // Message Type EXECUTE'
    ls04SetMCFlag(pSqlSegm, true);                               // Mass insert
    pSqlPart->sp1p_part_kind().becomes(sp1pk_parsid);


    // Insert parse id part
    rc = ls04BufToPart(pSqlPart, pszParseID, MAX_PARSEID_LENGTH_LS00);    // do not write trailing NULL
    if (errOK_els00 == rc)
    {
        rc = ls04FinishPart(pSqlPacket, pSqlPart);
    }

    // insert resultcount part
    if (errOK_els00 == rc)
    {
        rc = ls04InitPart(pSqlPacket, pSqlSegm, &pSqlPart, sp1pk_resultcount);
        if (errOK_els00 == rc)
        {
            rc = ls04BufToPart(pSqlPart,REINTERPRET_CAST(tsp00_Addr, pszResultCount), sizeof(csp_rescnt_unknown));
            if (errOK_els00 == rc)
            {
                rc = ls04FinishPart(pSqlPacket, pSqlPart);
            }
        }
    }

    // insert DATA part
    if (errOK_els00 == rc)
    {
        pSqlPart = NULL;
        rc = ls04InitPart(pSqlPacket, pSqlSegm, &pSqlPart, sp1pk_data);
        if (errOK_els00 != rc)
        {
            // Set part attribute for the first time (always: partattr = firstpacket)
            ls04SetPartAttribute(pSqlPart, PartAttribute);
        }
    }

    // static cast:IA64
    pOIPacketInitBlock.strLeng_ls00 = PartHSize_ls00 +
                                        STATIC_CAST(tsp00_Int4, REINTERPRET_CAST(char*, pSqlPart) - REINTERPRET_CAST(char*, pSqlPacket));

    //*
    //*     Allocate space for initial block in order interface packet that may be reused
    //*     for every single DATA packet sent to the kernel while inserting DATA for one single table
    //*
    pOIPacketInitBlock.strAddr_ls00 = new char[pOIPacketInitBlock.strLeng_ls00];
    SAPDB_memcpy(pOIPacketInitBlock.strAddr_ls00, (char*) &pSqlPacket->sp1_header, pOIPacketInitBlock.strLeng_ls00);

    // Initialize working buffer with the size of the DATA part
    pDataPartBuffer->lBufSize_ls00 = pSqlPart->sp1p_buf_size();
    pDataPartBuffer->lBufLen_ls00  = 0;
    pDataPartBuffer->pBufPtr_ls00  = new unsigned char[pDataPartBuffer->lBufSize_ls00];

    return rc;
}
// ls20InitializeOIPacket()


/*
  -----------------------------------------------------------------------------
  function:     ls20ReadData
  -----------------------------------------------------------------------------
*/
tsp00_Int4
ls20ReadData(tls00_VFile*      pInfile,
             tls00_FileFormat* pFileFormat,
             tls00_Pattern*    pPattern,
             tls00_MetaData*   pMeta,
             tls00_Buffer2*    pBuffer,
             SAPDB_Bool*       pbTabLoaded,
             SAPDB_Bool        bFirstRecord,
             tsp00_Addr        pszErrText)

{
    ROUTINE_DBG_MEO00 ("ls20ReadData");

    tsp00_Int4 rc = errOK_els00;

    tsp00_Int4          rlen   = 0;
    tsp00_SwapKind_Enum DSwap  = ls07DefineSwap(NULL);

    if (true == pFileFormat->ffoCompact_ls00)
    {
        // In case of file format RECORDS the DATA file has the following structure where
        // the long DATA is only optional if the table has long columns
        //|------------------------------------------------------------------------------------ ...
        //| meta data1 | data1 | [long data1] | meta data2 | data2 | [long data2] | meta data3 | ...
        //|------------------------------------------------------------------------------------...
        //
        // To minimize the file access we use the following strategy for tables with no
        // long columns:
        // During first read of the DATA (indicated by recordcount = 0) we read the first
        // meta data1 and compute the length of the corresponding data1. Then we read
        // immediately afterwards this data1 because we know the length and the next meta data2 at once.
        // The length of the meta DATA is fix for the whole file. The meta data2 is kept
        // then until this function is entered next time. Then we compute the length of data2
        // and read data2 and the next meta data3 at once and so on.
        //
        // For tables with long columns we first read the meta data1 and compute the length
        // of the data1. Then we read only data1 and process it. Thus in this case meta DATA
        // and DATA is read separately.


        // check for last DATA record; in this case do not read meta DATA of next record either;

        // compute meta DATA length
        rlen = pMeta->mdLengthArrayLen_ls00 * sizeof(tsp00_Uint2);

        if ( (true == bFirstRecord) || (pMeta->mdLongFieldCount_ls00 > 0) )
        {
            // Check if we read at the right position
            if ( (false == bFirstRecord) &&
                 ( (pMeta->pmdMetaFile_ls00->vfFilePos_ls00.lnu2GB_Blocks_ls00 != pMeta->mdPosOfNextLengthArray_ls00.lnu2GB_Blocks_ls00) ||
                   (pMeta->pmdMetaFile_ls00->vfFilePos_ls00.lnuRemainder_ls00 != pMeta->mdPosOfNextLengthArray_ls00.lnuRemainder_ls00) ) )
            {
                ls30VFSeekLong(*pMeta->pmdMetaFile_ls00, &pMeta->mdPosOfNextLengthArray_ls00, pszErrText);
            }

            // read meta information
            tsp00_Int4 len = ls30VFReadLnEx(*pMeta->pmdMetaFile_ls00, REINTERPRET_CAST(_TCHAR*, pMeta->pmdLengthArray_ls00), pszErrText, rlen);  //pMeta->mdLengthArrayLen_ls00 * sizeof(tsp00_Uint2));

            len >= 0 ?  rc = errOK_els00 : rc = len ;
        }
        else
        {
            // save meta information
            SAPDB_memcpy(pMeta->pmdLengthArray_ls00, &(STATIC_CAST(char*, pBuffer->pBufPtr_ls00)[pMeta->mdRecordLength_ls00]), rlen);
        }

        if (errOK_els00 == rc)
        {
            ls20ReadDataLength(pMeta, DSwap, pszErrText);

            if ( pMeta->pmdLengthArray_ls00[0] == STOP_NOMORE_DATA_LS00  )
            {
                if ( errOK_els00 == rc )
                {
                    *pbTabLoaded  = true;
                    rc  = STOP_NOMORE_DATA_LS00;
                }
            }
            else
            {
                if  (pMeta->mdLongFieldCount_ls00 > 0)
                {
                    rlen  = pMeta->mdRecordLength_ls00;
                }
                else
                {
                    rlen += pMeta->mdRecordLength_ls00;
                }
            }
        }
    } // if (true == pFileFormat->ffoCompact_ls00)
    else
    {
        rlen = pFileFormat->ffoBytesPerLine_ls00;
    }


    // Read the real DATA. In case of compact format we read the meta information of
    // the next record at this time, too.
    if ( (errOK_els00 == rc) || (STOP_LAST_DATA_LS00 == rc) )
    {
        SAPDB_Bool bNLInData = SAPDB_FALSE;
        SAPDB_Int4 len = 0;

        pBuffer->lBufPos_ls00 = 0;      // initialize
        
        do
        {
            len = ls30VFReadLnEx(*pInfile,       // read one row in DATA file
                                 &(STATIC_CAST(char*, pBuffer->pBufPtr_ls00)[pBuffer->lBufPos_ls00]),
                                 pszErrText,
                                 rlen,
                                 pBuffer->lBufLen_ls00 - pBuffer->lBufPos_ls00);
            if (0 > len)
            {
                if ( EOF_LS00 == len )
                {
                    rc  = STOP_NOMORE_DATA_LS00;    // InputLen = EOF_LS00 (= -1)
                }
                else
                {
                    rc = len;                       // InputLen = errFileRead_els98 in case of read error
                }
            }
            else
            {
                if (true == pFileFormat->ffoCompact_ls00)
                {
                    if (len < rlen)
                    {
                        // Coming here we could not read the DATA and the next meta DATA as
                        // requested. This can only mean that the file is fully read. We format
                        // the length array buffer area to 0 to force a EOF_LS00 answer when
                        // executing the read the next time.
                        memset(&(STATIC_CAST(char*, pBuffer->pBufPtr_ls00)[len]),
                               0,
                               pMeta->mdLengthArrayLen_ls00 * sizeof(tsp00_Uint2));
                        rc = STOP_LAST_DATA_LS00;
                    }
                }
                else
                {
                    pBuffer->lBufPos_ls00 += len;

                    // It's not the proprietary format: so try to find out if there is some
                    // newline in the DATA. If so read the next line and do the same until
                    // we find the closing newline character.
                    // Exclude reading binary and the FORMATTED format. In the latter case we
                    // can not with absolute certainty decide
                    // whether the row is simply that short or the DATA contains new line characters.
                    if ( (true == pFileFormat->ffoCompress_ls00) &&
                         (false == pFileFormat->ffoBinary_ls00)    &&
                         (0     != *pFileFormat->ffoDelimit_ls00)   )
                    {
                        // The given pBuffer has a initial length of 32 kByte. We have to check this
                        // to prevent buffer overflows
                        bNLInData = ls18CheckForNLInData(pBuffer, pPattern, pFileFormat);
                    }
                }
            }   // end else of if (0 > len)
        }
        while ( (SAPDB_TRUE == bNLInData) && (errOK_els00 == rc) );
    }   // end if (errOK_els00 == rc)

    return rc;
}
// ls20ReadData()


/*
  -----------------------------------------------------------------------------
  function:     ls20ReadDataLength
  -----------------------------------------------------------------------------
*/
void
ls20ReadDataLength(tls00_MetaData *pMeta, tsp00_SwapKind_Enum DSwap, tsp00_Addr pszErrText)
{
    //  This function is used to transform the length of DATA fields in case of
    //  file format RECORDS to the right swapped values and to compute the record length.
    //  The DATA is structured as follows
    //|------------------------------------------------------------------------------------ ...
    //| meta data1 | data1 | [long data1] | meta data2 | data2 | [long data2] | meta data3 | ...
    //|------------------------------------------------------------------------------------...
    //
    // meta data1 contains the length of all data1 and long data1 fields. Every DATA field
    // is characterized by a 2 byte integer length whereas every long DATA field is
    // characterized by a 4 byte integer. NULL values are indicated by a length of -12.
    // All length fields are signed integers.
    // The length values are swapped in the current machine swap.
    //
    // This function computes the record length, too. Because of negative length of NULL values
    // this length is not added to the record length. Additionally the length of long
    // values is also not added to the record length because longs are handled separately.

    ROUTINE_DBG_MEO00 ("ls20ReadDataLength");

    pMeta->mdRecordLength_ls00 = 0;
    if (pMeta->mdLongFieldCount_ls00 > 0)
    {
        // First part (easy): set position to file position AFTER the length array
        // because this has already been read coming here
        pMeta->mdPosOfNextLengthArray_ls00.lnu2GB_Blocks_ls00 = pMeta->pmdMetaFile_ls00->vfFilePos_ls00.lnu2GB_Blocks_ls00;
        pMeta->mdPosOfNextLengthArray_ls00.lnuRemainder_ls00  = pMeta->pmdMetaFile_ls00->vfFilePos_ls00.lnuRemainder_ls00;
    }

    tsp00_Uint4 i       = 0;
    tsp00_Uint4 j       = 0;
    tsp00_Int4  LongLen = 0;
    bool        bLong   = false;
    for (i,j; i < pMeta->mdFieldCount_ls00; ++i)
    {
        if (j < pMeta->mdLongFieldCount_ls00)
        {
            if ((i+1) == pMeta->pmdLongFieldPos_ls00[j])
            {
                SAPDB_memcpy(&LongLen, &(pMeta->pmdLengthArray_ls00[i+j]), sizeof(tsp00_Int4));
                if (DSwap != pMeta->mdSwapKind_ls00)
                {
                    ls07Swap4BCharInPlace(REINTERPRET_CAST(tsp00_Addr, &LongLen), pMeta->mdSwapKind_ls00, DSwap);
                    SAPDB_memcpy(&(pMeta->pmdLengthArray_ls00[i+j]), &LongLen, sizeof(tsp00_Int4));
                }
                TRACE_PRNF_MLS99(("ls20ReadDataLength", "Long value length: %d", LongLen));

                // Second part: add length of this long to position of next record
                if (INSERT_NULL != LongLen)
                {
                    ls07AddLargeNumbers(pMeta->mdPosOfNextLengthArray_ls00, LongLen);
                }
                bLong = true;
            }
        }

        if (false == bLong)
        {
            if (DSwap != pMeta->mdSwapKind_ls00)
            {
                pMeta->pmdLengthArray_ls00[i+j] = ls07Swap2BInt(pMeta->pmdLengthArray_ls00[i+j],
                                                                pMeta->mdSwapKind_ls00, DSwap);
            }
            if (INSERT_NULL != pMeta->pmdLengthArray_ls00[i+j])     // NULL-value; do not add length to record length
            {
                pMeta->mdRecordLength_ls00 += pMeta->pmdLengthArray_ls00[i+j];
            }
            TRACE_PRNF_MLS99(("ls20ReadDataLength", "vallen=%d", pMeta->pmdLengthArray_ls00[i+j]) );
        }
        else
        {
            bLong = false;
            ++j;
        }
    } //while (i < pMeta->mdLengthArrayLen_ls00);

    // Third part: add length of this record without LONGs (these have already been added) to position of next record
    ls07AddLargeNumbers(pMeta->mdPosOfNextLengthArray_ls00, pMeta->mdRecordLength_ls00);

    return;
}
// ls20ReadDataLength()

/*
  -----------------------------------------------------------------------------
  function:     ls20BuildRecord
  -----------------------------------------------------------------------------
*/
tsp00_Longint
ls20BuildRecord(tls00_DataSource       *pDataSource,
                tls00_Buffer           *pDataPartBuffer,
                tls00_TableDescription *pTableDesc,
                tls00_MultColSpec      *pMultCol,
                tls00_LongExecInfo     *pLongExecInfo,
                bool                    bUnicodeOI,
                tsp00_Int4              RecordCount,
                tsp00_Addr              pszErrText)
{
    ROUTINE_DBG_MEO00 ("ls20BuildRecord");

    tsp00_Longint     rc         = errOK_els00;
    tsp00_Int4        lResult    = 0;
    unsigned char*    pColValue  = NULL;
    tls00_Column*     pColumn    = NULL;
    tls00_ParamInfo*  pPI        = NULL;
    tls00_String*     RawData    = pDataSource->dasConvertedData;
    unsigned char*    pszBuffer  = &(STATIC_CAST(unsigned char*, pDataPartBuffer->pBufPtr_ls00)[pDataPartBuffer->lBufLen_ls00]);

    for(tsp00_Int4 i=0; (i < pTableDesc->tdFieldCount_ls00) && (rc >= 0); ++i)
    {
        pColumn = pMultCol->mcsColumn_ls00[pDataSource->plDataToColIndex_ls00[i]];

        // Even if loop index i corresponds exactly plDataToParamIndex_ls00[i] for DATALOAD
        // commands we need it here as we use this function for DATAUPDATE also; for DATAUPDATE
        // both indexes are not the same
        pPI       = pTableDesc->tdParamArray_ls00[pDataSource->plDataToParamIndex_ls00[i]];

        // Points to undef-byte before bufpos for value to build
        pColValue = pszBuffer + (pPI->piBufpos_ls00 - 1);

        lResult = ls20_ValueToOIBuffer(RawData[i],
                                       *pPI,
                                       pColumn,
                                       pDataSource->dasCodeType_ls00,
                                       pDataSource->pdasCodePage_ls00,
                                       bUnicodeOI,
                                       pColValue,
                                       pszErrText);
        if (lResult >= 0)
        {
            // Additional check/work for LONGs: if NOT NULL increase counter
            if ( (1           == szMap_LongDataType_ls00[pPI->piBasicInfo_ls00.fbDataType_ls00]) &&
                 (INSERT_NULL != RawData[i].strLeng_ls00) )
            {
                pLongExecInfo->dliNNLongs_ls00[pLongExecInfo->dliCntNNLongs_ls00] = i;
                ++pLongExecInfo->dliCntNNLongs_ls00;
            }
        }
        else    // OOOPs, error --> adapt return value, too!
        {
            LoaderMessages *pMsgObj = LoaderMessages::Instance(); // error msg obj

            pMsgObj->ls98Msg(layDataLoad_els98, pszErrText, errAtRow_els98, RecordCount);
            pMsgObj->ls98Msg(layDataLoad_els98, pszErrText, STATIC_CAST(ErrorNumbers, lResult),
                                                            pTableDesc->tdColName_ls00[i]->asCharp());
            rc = lResult;
        }
    }   // end for(tsp00_Int4 i=0; (i < pTableDesc->tdFieldCount_ls00) && (rc >= 0); ++i)

    return rc;
}
// ls20BuildRecord()

/*!
  -----------------------------------------------------------------------------
  function:     ls20_ValueToOIBuffer
  -----------------------------------------------------------------------------
*/
tsp00_Int4
ls20_ValueToOIBuffer(tls00_String        &pInputData,            // = RawData
                     tls00_ParamInfo     &ParameterInfo,
                     tls00_Column        *pColumn,
                     tls00_CodeType       DataFileEncoding,
                     tsp81_CodePage      *pCodePageTable,
                     bool                 bUnicodeOI,
                     unsigned char       *pOIValueBuffer,
                     tsp00_Addr           pszErrText)
{
    ROUTINE_DBG_MEO00 ("ls20_ValueToOIBuffer");

    tsp00_Longint  rc       = 0;
    tsp00_Int4     lResult  = 0;
    tsp00_Longuint lDestLen = 0;

    tls00_FieldBasics   BasicInfo = ParameterInfo.piBasicInfo_ls00;

    switch(pInputData.strLeng_ls00)
    {
        case INSERT_DEFAULT:
        {
            *pOIValueBuffer = csp_default_byte;
            break;
        }
        case INSERT_NULL:
        {
            *pOIValueBuffer = csp_undef_byte;
            break;
        }
        case INSERT_EMPTY_VALUE:
        {
            *pOIValueBuffer = ls07GetDefByte(BasicInfo.fbDataType_ls00);     // Insert defined-byte
            if (1 == szMap_LongDataType_ls00[BasicInfo.fbDataType_ls00])
            {
                // Initialize Longdescriptor to vm_nodata
                tsp00_LongDescriptor LongDescriptor;
                ls08InitLONGDescriptor(&LongDescriptor);
                SAPDB_memcpy((pOIValueBuffer + 1), &LongDescriptor, LongDescSize_ls00);
            }
            else
            {
                // length parameter counts the defined byte
                ls05InsertFillBytes(pOIValueBuffer,
                                    lResult + sizeof(char),
                                    BasicInfo.fbDataType_ls00,
                                    BasicInfo.fbInOutLength_ls00,
                                    bUnicodeOI,
                                    SERVER_SWAPPING_LS00);
            }
            break;
        }
        default:
        {
            *pOIValueBuffer = ls07GetDefByte(BasicInfo.fbDataType_ls00);     // Insert defined-byte

            if (1 == szMap_LongDataType_ls00[BasicInfo.fbDataType_ls00])
            {
                // Initialize Longdescriptor to vm_nodata
                tsp00_LongDescriptor LongDescriptor;
                ls08InitLONGDescriptor(&LongDescriptor);
                SAPDB_memcpy((pOIValueBuffer + 1), &LongDescriptor, LongDescSize_ls00);
            }
            else
            {
                if ( (true == bUnicodeOI) && (true == bUnicodeOverOI_ls00[BasicInfo.fbDataType_ls00]) )
                {
                    // coming here only char DATA types, blobs or date, time and timestamp arrive
                    // char must not be converted if the DataFileEncoding is already UCS2
                    //
                    // DATE, TIME and TIMESTAMP must always be converted because the internal routines
                    // to convert the representation to ISO, ... work only with ascii DATA;
                    // But this conversion needs only code page ISO8859-1 - ever. So don't give any
                    // code page info to the conversion routine.
                    if (1 == szMap_SpecConstDataType_ls00[BasicInfo.fbDataType_ls00])
                    {
                        lDestLen = BasicInfo.fbInOutLength_ls00;

                        rc = ls05ConvertToUCS2Simple(pOIValueBuffer + 1,
                                                     lDestLen,
                                                     REINTERPRET_CAST(unsigned char*, pInputData.strAddr_ls00),
                                                     pInputData.strLeng_ls00,
                                                     ctAscii_els00,
                                                     pszErrText);
                        if (errOK_els00 == rc)
                        {
                            lResult = STATIC_CAST(tsp00_Int4, lDestLen);
                        }
                    }
                    else
                    {
                        // char DATA already in UCS2 must not be converted again, but may be swapped;
                        // char DATA UTF8 or ASCII encoded must be converted here
                        if ( false == ls00IsUCS2(&DataFileEncoding) )
                        {
                            lDestLen = BasicInfo.fbInOutLength_ls00;

                            rc = ls05ConvertToUCS2(pOIValueBuffer + 1,
                                                   lDestLen,
                                                   REINTERPRET_CAST(unsigned char*, pInputData.strAddr_ls00),
                                                   pInputData.strLeng_ls00,
                                                   DataFileEncoding,
                                                   BasicInfo.fbDataType_ls00,
                                                   pszErrText,
                                                   pCodePageTable);
                            if (errOK_els00 == rc)
                            {
                                lResult = STATIC_CAST(tsp00_Int4, lDestLen);
                            }
                        }
                        else
                        {
                            SAPDB_memcpy(pOIValueBuffer + 1, pInputData.strAddr_ls00, pInputData.strLeng_ls00);
                            lResult = pInputData.strLeng_ls00;
                            
                            if ( ( (sw_full_swapped == SERVER_SWAPPING_LS00) && (ctUCS2_els00 == DataFileEncoding) )
                                 ||
                                 ( (sw_normal == SERVER_SWAPPING_LS00)       && (ctUCS2Swapped_els00 == DataFileEncoding) ) )
                            {
                                ls07SwapUCS2StringInPlace(REINTERPRET_CAST(char*, (pOIValueBuffer + 1)), pInputData.strLeng_ls00);
                            }
                        }
                    }

                }   // end if ( (true == bUnicodeOI) && (true == bUnicodeOverOI_ls00[BasicInfo.fbDataType_ls00]) )
                else
                {
                    SAPDB_memcpy(pOIValueBuffer + 1, pInputData.strAddr_ls00, pInputData.strLeng_ls00);
                    lResult = pInputData.strLeng_ls00;
                }

                if (lResult >= 0)
                {
                    // length parameter counts the defined byte
                    ls05InsertFillBytes(pOIValueBuffer,
                                        lResult + sizeof(char),
                                        BasicInfo.fbDataType_ls00,
                                        BasicInfo.fbInOutLength_ls00,
                                        bUnicodeOI,
                                        SERVER_SWAPPING_LS00);
                }
            }
            break;
        }
    } // End OF SWITCH RAWDATA TYPE

    return lResult;
}
// ls20_ValueToOIBuffer()


/*!
  -----------------------------------------------------------------------------
  function:     ls20ConvertValue2InternEncoding
  -----------------------------------------------------------------------------
*/
tsp00_Longint
ls20ConvertValue2InternEncoding(tls00_String        &RawData,
                                tsp00_DataType_Enum  DataType,
                                tls00_CodeType       CodeType,
                                tsp00_Addr           pszErrText)
{
    ROUTINE_DBG_MEO00 ("ls20ConvertValue2InternEncoding");

    tsp00_Longint rc = 0;

    //*
    //*     FIRST TRANSFORMATION of delivered value: bring it into 'internal'
    //*     encoding (ascii so far) to process it if the external encoding
    //*     is UNICODE (i.e. UCS2 or UTF8).
    //*
    //* Transformation to 'internal' encoding for values of type
    //*  - date, time, timestamp (value must be brought into the right format and
    //*    transformation routines may only handle ascii DATA)
    //*  - boolean - delivered as external user defined representation
    //*  - numeric - delivered as readable value
    //*  - blobs   - delivered in readable hex notation
    //*  - long    - DATA file contains meta information on real long values located
    //*              in long files; this meta information has to be converted; the real
    //*              longs are gotten later when processing the descriptor
    //* No transformation for values of all other types because
    //*  - char/varchar - transformed later with regards to the external representation
    bool bConversionNecessary = true;
    if (1 == szMap_CharDataType_ls00[DataType])
    {
         if (0 == szMap_BlobDataType_ls00[DataType])
         {
             bConversionNecessary = false;
         }
         else
         {
             if (ctUTF8_els00 == CodeType)
             {
                 // In case of UTF8 BLOBs (i.e. readable hex notation) does not need to
                 // be converted because it is in any case US7ASCII
                 bConversionNecessary = false;
             }
         }
    }   // end if (1 == szMap_LongDataType_ls00[DataType])


    if (true == bConversionNecessary)
    {
        if (ctUTF8_els00 == CodeType)
        {
            tsp00_Longuint len = RawData.strLeng_ls00;

            rc = ls05ConvertFromUTF8(REINTERPRET_CAST(unsigned char*, RawData.strAddr_ls00),
                                     len,
                                     REINTERPRET_CAST(unsigned char*, RawData.strAddr_ls00),
                                     RawData.strLeng_ls00,
                                     ctAscii_els00,
                                     pszErrText);
            if (errOK_els00 == rc)
            {
                RawData.strLeng_ls00 = STATIC_CAST(tsp00_Int4, len);
            }
        }
        else if (true == ls00IsUCS2(&CodeType))
        {
            tsp00_Longint lConversionBufLen = RawData.strLeng_ls00;

            rc = ls05ConvertFromUCS2Simple(REINTERPRET_CAST(unsigned char*, RawData.strAddr_ls00),
                                           REINTERPRET_CAST(unsigned char*, RawData.strAddr_ls00),
                                           lConversionBufLen,
                                           RawData.strLeng_ls00,
                                           ctAscii_els00,
                                           CodeType,
                                           pszErrText);
            if (errOK_els00 == rc)
            {
                RawData.strLeng_ls00 = STATIC_CAST(tsp00_Int4, lConversionBufLen);
            }
        }
    }   // end if (true == bConversionNecessary)

    return rc;
}
// ls20ConvertValue2InternEncoding()

/*
  -----------------------------------------------------------------------------
  function:     ls20TransformColumnValue
  -----------------------------------------------------------------------------
*/
tsp00_Longint
ls20TransformColumnValue(tls00_String        *pRawValue,
                         tls00_Column        *pColumn,
                         tls00_Buffer2       *pInputBuffer,
                         tls00_ParamInfo     *pParamInfo,
                         tls00_FileSpec      *pFileSpec,
                         tsp00_SwapKind_Enum  SwapKind,
                         tsp1_sqlmode_Enum    SQLMode,
                         tls00_Pattern*       pPattern,
                         tsp00_Addr           pszErrText)
{
    ROUTINE_DBG_MEO00 ("ls20TransformColumnValue");

    LoaderMessages *pMsgObj = LoaderMessages::Instance();    // error reporting obj
    tsp00_Longint    rc      = errOK_els00;

    tls00_FileFormat *pFileFormat = &pFileSpec->fsFormat_ls00;
    tls00_String     tmpStr;

    // last (INSERT_NULL) is valid only for fileformat COMPACT
    if ( (INSERT_EMPTY_VALUE != pRawValue->strLeng_ls00) && (INSERT_NULL != pRawValue->strLeng_ls00) )
    {
        if ( (true         == pFileFormat->ffoCompress_ls00) &&
             (ioChar_els00 == pColumn->colFormat_ls00.ffoFormat_ls00) &&
             (1            == szMap_CharDataType_ls00[pParamInfo->piBasicInfo_ls00.fbDataType_ls00]) &&
             (1            != szMap_BlobDataType_ls00[pParamInfo->piBasicInfo_ls00.fbDataType_ls00])  )
        {
            ls18UndoubleDelimitersInCharData(pRawValue, pPattern, pFileFormat->ffoCodeType_ls00);
        }

        //*
        //*     Trim values right - remove trailing blanks
        //* Done for LONG DATA that is of external DATA type CHAR in case of format COMPRESSED and FORMATTED
        //* these values in the DATA file are simply positions specs and can be trimmed
        //*
        if ( (false == pFileFormat->ffoCompact_ls00) && (ioChar_els00 == pColumn->colFormat_ls00.ffoFormat_ls00) )
        {
            if ( (true == pFileFormat->ffoFormatted_ls00) ||    //http://pts:1080/webpts?wptsdetail=yes&ErrorType=0&ErrorID=1118955
                 ( (true == pFileFormat->ffoCompress_ls00)   &&
                   (1    == szMap_LongDataType_ls00[pParamInfo->piBasicInfo_ls00.fbDataType_ls00]) ) )
            {
                tsp00_Longint len  = pRawValue->strLeng_ls00;
                // Handle byte values in files with FORMATTED BINARY differently from not binary
                // formatted files
                if ( (true == pFileFormat->ffoFormatted_ls00) && (true == pFileFormat->ffoBinary_ls00) &&
                     (1    == szMap_BlobDataType_ls00[pParamInfo->piBasicInfo_ls00.fbDataType_ls00]) &&
                     (0    == szMap_LongDataType_ls00[pParamInfo->piBasicInfo_ls00.fbDataType_ls00]) &&
                     (false == pColumn->colFormat_ls00.ffoIsHex_ls00) )
                {
                    ls05StrTrimRight(pRawValue->strAddr_ls00, len, '\0', pFileFormat->ffoCodeType_ls00);
                }
                else
                {
                    ls05StrTrimRight(pRawValue->strAddr_ls00, len, BLANK_LS00, pFileFormat->ffoCodeType_ls00);
                }

                // In case of format FORMATTED trimming prevents from errors where the DATA field exceeds
                // the allowed column length but only because it is padded with blanks;
                // but if the DATA consists entirely of blanks we'll retain it here
                if (len > 0)        // http://pts:1080/webpts?wptsdetail=yes&ErrorType=0&ErrorID=1124555
                {
                    pRawValue->strLeng_ls00 = STATIC_CAST(tsp00_Int4, len);
                }
            }
        }   // end if ( (false == pFileFormat->ffoCompact_ls00) && (ioChar_els00 == pColumn->colFormat_ls00.ffoFormat_ls00) )

        // Check for NULL DEFINITION
        // NULL condition may be checked only for not COMPACT formats. In case of COMPACT format
        // the NULL value is already given with the read DATA - here the length has the
        // value -12 = INSERT_NULL
        // A NULL condition is specified in the load command if the null condition value is not NULL itself
        if ( (errOK_els00 == rc) && (NULL != pColumn->colNullCond_ls00) && (false == pFileFormat->ffoCompact_ls00) )
        {
            tmpStr.strAddr_ls00 = STATIC_CAST(char*, pInputBuffer->pBufPtr_ls00);
            tmpStr.strLeng_ls00 = pInputBuffer->lBufPos_ls00;
            rc = ls24GetNILConstants(*pRawValue,
                                     tmpStr,
                                     pParamInfo->piMode_ls00,
                                     *pColumn->colNullCond_ls00,
                                     *pFileFormat);
            if (errNullNotAllowed_els98 == rc)
            {
                pMsgObj->ls98MsgToString(layDataLoad_els98, pszErrText,
                                                            STATIC_CAST(ErrorNumbers,rc),
                                                            pColumn->colName_ls00.asCharp());
            }
            // In case the NULL-check went without problems we have 2 cases to distinguish:
            // 1. there is a null-value --> leave the function (pRawValue->strLeng_ls00 is set to INSERT_NULL)
            // 2. there is a real value --> continue processing value
        }

        if ( (errOK_els00 == rc) && (INSERT_NULL != pRawValue->strLeng_ls00) )
        {
            //*
            //*     Convert values to internal encoding (ASCII) for further processing
            //*
            if ( (ctAscii_els00 != pFileFormat->ffoCodeType_ls00 )         &&
                (ioChar_els00  == pColumn->colFormat_ls00.ffoFormat_ls00) &&
                ((true          != pFileFormat->ffoCompact_ls00  )         ||
                ((true          == pFileFormat->ffoCompact_ls00  )         &&
                (0             == szMap_LongDataType_ls00[pParamInfo->piBasicInfo_ls00.fbDataType_ls00] )) ))
            {
                rc = ls20ConvertValue2InternEncoding(*pRawValue,
                                                     pParamInfo->piBasicInfo_ls00.fbDataType_ls00,
                                                     pFileFormat->ffoCodeType_ls00,
                                                     pszErrText);
            }

            //* Check for:
            //*  - hex representation of DATA -> convert it; exclude LONG specs in DATA file because
            //*    those are only meta DATA to the real long values in the long files which are
            //*    handled later
            //*  - NULL value representation
            //*  - LONGs
            //*  - specials like DATE, TIME, TIMESTAMP, BOOLEAN
            //*  - NUMBER (convert to internal db format)

            // (DATA in HEX form) or (BLOB DATA type and file format is not binary)?

            if (errOK_els00 == rc)
            {
                if ( ( (true == pColumn->colFormat_ls00.ffoIsHex_ls00) &&
                    (0 == szMap_LongDataType_ls00[pParamInfo->piBasicInfo_ls00.fbDataType_ls00]) )
                    ||
                    ( (1 == szMap_BlobDataType_ls00[pParamInfo->piBasicInfo_ls00.fbDataType_ls00]) &&
                    (0 == szMap_LongDataType_ls00[pParamInfo->piBasicInfo_ls00.fbDataType_ls00]) &&
                    (false == pFileFormat->ffoBinary_ls00) ) )
                {                                                       // -->  convert to byte
                    tsp00_Addr  pNewValue = NULL;
                    tsp00_Int4  lNewValueLen = 0;

                    rc = ls07ConvertHexToByte(pRawValue->strAddr_ls00, pRawValue->strLeng_ls00,
                                            &pNewValue,              lNewValueLen);
                    if (errOK_els00 != rc)
                    {
                        pMsgObj->ls98MsgToString(layDataLoad_els98, pszErrText, STATIC_CAST(ErrorNumbers,rc),
                                                                                pRawValue->strLeng_ls00,
                                                                                pRawValue->strAddr_ls00);
                    }
                    else
                    {
                        pRawValue->strAddr_ls00 = pNewValue;
                        pRawValue->strLeng_ls00 = lNewValueLen;
                    }
                }
            }

            // Process LONG value?
            if (1 == szMap_LongDataType_ls00[pParamInfo->piBasicInfo_ls00.fbDataType_ls00])
            {
                TRACE_PRNF_MLS99(("ls20TransformColumnValue", "Long value found\n") );

                // There need to be DATA
                if ( (pRawValue->strLeng_ls00 >= 0) && (false == pFileFormat->ffoCompact_ls00) )
                {
                    rc = ls08ReadLongFileInfo(pColumn, pParamInfo, pRawValue, pszErrText);
                    if (errOK_els00 != rc)
                    {
                        if( (errFileClose_els98 != rc) && (errFileOpen_els98 != rc) && (errFileRead_els98 != rc) )
                        {
                            pMsgObj->ls98MsgToString(layDataLoad_els98, pszErrText, errLongfileSpecMissing_els98);
                        }
                    }
                }
            }
            else
            {
                if (1 == szMap_NumberDataType_ls00[pParamInfo->piBasicInfo_ls00.fbDataType_ls00])
                {                                                       // --> convert to internal db format
                    rc = ls25PrepareNumbers(&pRawValue->strAddr_ls00,
                                            pRawValue->strLeng_ls00,
                                            *pColumn,
                                            pParamInfo->piBasicInfo_ls00,
                                            SwapKind,
                                            *pFileFormat);
                    if (errOK_els00 != rc)
                    {
                        if (errNumberTruncated_els98 != rc)
                        {
                            pMsgObj->ls98MsgToString(layDataLoad_els98, pszErrText, STATIC_CAST(ErrorNumbers, rc),
                                                                                    pRawValue->strLeng_ls00,
                                                                                    pRawValue->strAddr_ls00);
                        }
                    }
                }
                else if (1 == szMap_SpecConstDataType_ls00[pParamInfo->piBasicInfo_ls00.fbDataType_ls00])
                {

                    rc = ls24SpecialFormat(*pRawValue, pParamInfo->piBasicInfo_ls00, *pFileFormat);
                    if (errOK_els00 != rc)
                    {
                        pMsgObj->ls98MsgToString(layDataLoad_els98, pszErrText, STATIC_CAST(ErrorNumbers, rc),
                                                                                pRawValue->strLeng_ls00,
                                                                                pRawValue->strAddr_ls00);
                    }
                }
            }   // end else branch if (1 == szMap_LongDataType_ls00[pParamInfo->piBasicInfo_ls00.fbDataType_ls00])

        }   // end if ( (errOK_els00 == rc) && (INSERT_NULL != pRawValue->strLeng_ls00) )

    }   // end if ( (INSERT_EMPTY_VALUE != pRawValue->strLeng_ls00) && ...
    else if (INSERT_EMPTY_VALUE == pRawValue->strLeng_ls00)
    {
        // Coming here there is either no DATA found in DATA file for specified column or the value is
        // the empty value;
        // check if column has null condition (even an empty string may be defined
        // to represent the NULL value)
        if (NULL != pColumn->colNullCond_ls00)
        {
            tmpStr.strAddr_ls00 = STATIC_CAST(char*, pInputBuffer->pBufPtr_ls00);
            tmpStr.strLeng_ls00 = pInputBuffer->lBufPos_ls00;
            rc = ls24GetNILConstants(*pRawValue,
                                     tmpStr,
                                     pParamInfo->piMode_ls00,
                                     *pColumn->colNullCond_ls00,
                                     *pFileFormat);
        }

        // NULL-value check may reveal that the DATA is not the NULL value;
        // in this case the length remains unchanged (INSERT_EMPTY_VALUE)
        if (INSERT_EMPTY_VALUE == pRawValue->strLeng_ls00)
        {
            // nothing read but no null condition specified; check if DATA is of DATA type char
            // as this is the only data type that allows empty values
            if ( (1 == szMap_CharDataType_ls00[pParamInfo->piBasicInfo_ls00.fbDataType_ls00]) ||
                 (1 == szMap_BlobDataType_ls00[pParamInfo->piBasicInfo_ls00.fbDataType_ls00]) ||
                 (1 == szMap_LongDataType_ls00[pParamInfo->piBasicInfo_ls00.fbDataType_ls00]))
            {
                if (sp1sm_oracle == SQLMode)
                {
                    // if sqlmode = oracle an empty field means to insert NULL; check if it is defined
                    if ( true == pParamInfo->piMode_ls00.includes(sp1ot_optional) )
                    {
                        pRawValue->strLeng_ls00 = INSERT_NULL;
                    }
                    else
                    {
                        rc = errNullNotAllowed_els98;
                    }
                }
                // we're done here with the emptyness here; the rest is done in ls20_ValueToOIBuffer
            }
            else
            {
                rc = errMissingData_els98;
            }
        }

        if (errOK_els00 != rc)
        {
            pMsgObj->ls98MsgToString(layDataLoad_els98, pszErrText, STATIC_CAST(ErrorNumbers, rc),
                                                                    pColumn->colName_ls00.asCharp());
        }
    }   // end else of if (INSERT_DEFAULT != pRawValue->strLeng_ls00)


    //*
    //* Check value length
    //* Length of number values will be checked twice because it is first time check at conversion
    //* --> doesn't matter
    //*
    if ( (errOK_els00 == rc) &&
         (pRawValue->strLeng_ls00 >= 0) &&          // Exclude the case where the value is empty or NULL
         (0 == szMap_LongDataType_ls00[pParamInfo->piBasicInfo_ls00.fbDataType_ls00]) &&
         (0 == szMap_NumberDataType_ls00[pParamInfo->piBasicInfo_ls00.fbDataType_ls00]) )
    {
        tsp00_Uint4 _len = pRawValue->strLeng_ls00;         // this is the length in Bytes but we need
                                                            // the length in characters

        if ( (1 == szMap_CharDataType_ls00[pParamInfo->piBasicInfo_ls00.fbDataType_ls00]) &&
             (ctAscii_els00 != pFileFormat->ffoCodeType_ls00) )
        {
            if (ctUTF8_els00 != pFileFormat->ffoCodeType_ls00)
            {
                _len /= 2;
            }
            else
            {
                unsigned int charLength       = 0;
                unsigned int byteLength       = 0;
                int          isTerminated     = 0;
                int          isCorrupted      = 0;
                int          isExhausted      = 0;

                sp77encodingUTF8->stringInfo(pRawValue->strAddr_ls00,
                                             _len,
                                             1,
                                             &_len,
                                             &byteLength,
                                             &isTerminated,
                                             &isCorrupted,
                                             &isExhausted);
            }
        }
        rc = ls18CheckValueLength(_len, pParamInfo->piBasicInfo_ls00);
        if (rc != errOK_els00)
        {
            pMsgObj->ls98MsgToString(layDataLoad_els98, pszErrText, STATIC_CAST(ErrorNumbers, rc),
                                                                    pColumn->colName_ls00.asCharp());
        }
    }   // end if if ( (errOK_els00 == rc) && (0 == szMap_LongDataType_ls00[pParamInfo->piBasicInfo_ls00.fbDataType_ls00]) )

    return rc;
}
// ls20TransformColumnValue()


/*
  -----------------------------------------------------------------------------
  function:     ls20Recover
  -----------------------------------------------------------------------------
*/
void
ls20Recover(tls00_DataPartHandling *pHandling,
            tsp00_Int4              lLongColCnt,
            tls00_TableDescription *pTD,
            tsp00_Int4              &RowCount,
            tsp00_Int4              lErrorPos,
            bool                    &bPutVal)
{
    ROUTINE_DBG_MEO00 ("ls20Recover");

    tsp00_Int4 rc = errOK_els00;

    tls00_Buffer   *pBuffer   = &pHandling->dphBuffer_ls00;
    unsigned char  *pszBufPtr = STATIC_CAST(unsigned char*, pBuffer->pBufPtr_ls00);

    if (RowCount > lErrorPos)
    {
        tsp00_Int4 i = 0;
        tsp00_Int4 j = 0;

        //*
        //*     Move valid records in buffer to the beginning of the buffer overwriting
        //*     the already inserted and the erroneous one
        //*
        tsp00_Int4 lMoveDistance = pHandling->dphRecordSpace_ls00[lErrorPos - 1];

        memmove(&pszBufPtr[0],
                &pszBufPtr[lMoveDistance],
                (pHandling->dphRecordSpace_ls00[RowCount-1] - pHandling->dphRecordSpace_ls00[lErrorPos - 1]) );

        pBuffer->lBufSize_ls00 += lMoveDistance;                // adapt free
        pBuffer->lBufLen_ls00  -= lMoveDistance;                // and used space in packet buffer

        //*
        //*     Special treatment for long columns: adapt positions
        //*
        tsp00_Int4 *pLongIndex = NULL;
        if (0 != lLongColCnt)
        {
            //*
            //*     Get the indexes of longs in param array
            //*
            pLongIndex = new tsp00_Int4[lLongColCnt];
            for (i = 0, j = 0; i < pTD->tdFieldCount_ls00; ++i)
            {   //*     LONG column ?
                if (1 == szMap_LongDataType_ls00[pTD->tdParamArray_ls00[i]->piBasicInfo_ls00.fbDataType_ls00])
                {
                    pLongIndex[j] = i;
                    ++j;
                }
            }
        }

        //*
        //*     Adapt long descriptors in every single record and
        //*     adapt values for dlrRecordSpace_ls00 and dlrRecordNumbers_ls00
        //*
        //* Recalculate valpos (absolute value) and use the length of the long for computing the
        //* beginning of the next record in buffer. If the longs are all NULL the record length is
        //* the length to move the pointer to match the next record.
        //* In case the long descriptor indicates no long value in the buffer (ld_valmode() = vm_nodata)
        //* treat them as if they were NULL (the long length is not set).
        //*
        tsp00_Int4            lLongLen  = 0;
        tsp00_LongDescriptor  LongDesc;
        unsigned char         cLongColDefByte;
        unsigned char        *pszRecord = &pszBufPtr[0];   // initializing pszRecord to first record in packet buffer
                                                           // this ptr will be wandering through the buffer
        RowCount = RowCount - lErrorPos;
        for (i = 0; i < RowCount; ++i)
        {
            for (j = 0, lLongLen = 0; j < lLongColCnt; ++j)
            {
                // We need to subtract 1 from piBufPos_ls00 because Bufpos starts counting at 1!
                cLongColDefByte = *(pszRecord + pTD->tdParamArray_ls00[pLongIndex[j]]->piBufpos_ls00 - 1);

                // We need to copy the long descriptor before manipulating it to be
                // sure not to cause a crash when casting it to an odd memory address
                SAPDB_memcpy(&LongDesc, pszRecord + pTD->tdParamArray_ls00[pLongIndex[j]]->piBufpos_ls00, sizeof(tsp00_LongDescriptor));
                if ( (csp_undef_byte != cLongColDefByte) &&
                    (vm_nodata      != LongDesc.ld_valmode()) )
                {
                    LongDesc.ld_valpos() -= lMoveDistance;            // adapt valpos - absolute value
                    lLongLen             += LongDesc.ld_vallen();   // add len of THIS longvalue to lLongLen

                    // We need to move the descriptor back to its place
                    SAPDB_memcpy(pszRecord + pTD->tdParamArray_ls00[pLongIndex[j]]->piBufpos_ls00, &LongDesc, sizeof(tsp00_LongDescriptor));
                }
            }   // end for (j = 0, lLongLen = 0; j < lLongColCnt; ++j)

            pszRecord += lLongLen + pHandling->dphRecordLength_ls00;

            pHandling->dphRecordNumbers_ls00[i] = pHandling->dphRecordNumbers_ls00[i + lErrorPos];
            pHandling->dphRecordSpace_ls00[i]   = pHandling->dphRecordSpace_ls00[i + lErrorPos] - lMoveDistance;
        }

        if (NULL != pLongIndex)
        {
            delete [] pLongIndex;
            pLongIndex = NULL;
        }
    }
    else        //if (RowCount > lErrorPos)
    {
        // Ok, all rows of a packet are inserted -> reset row counter to 0
        pBuffer->lBufSize_ls00 = pBuffer->lBufLen_ls00 + pBuffer->lBufSize_ls00;  // adapt free space in packet buffer
        pBuffer->lBufLen_ls00  = 0;
        bPutVal                = false;                                           // reset bPutVal
        RowCount               = 0;
    }

    return;
}
// ls20Recover()

/*
  -----------------------------------------------------------------------------
   End Chapter Global functions: implementation
  -----------------------------------------------------------------------------
*/

/*
  -----------------------------------------------------------------------------
   Begin Chapter Local functions: implementation
  -----------------------------------------------------------------------------
*/

/*
  -----------------------------------------------------------------------------
  function:     ls20_CheckHeader
  -----------------------------------------------------------------------------
*/
static tsp00_Int4
ls20_CheckHeader(tls00_DBInfo            *pDBInfo,
                 tls00_TransformationCmd *pDatLoadCmd,
                 Tools_DynamicUTF8String  DatExtrStmt,
                 tsp00_Addr               ErrText)
{
    ROUTINE_DBG_MEO00 ("ls20_CheckHeader");

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

    tls00_Command *pSvrCmd = new tls00_Command;
    memset (pSvrCmd, DEF_BYTE_LS00, sizeof(tls00_Command));

    // initialize the request string
    pSvrCmd->cmdReqDat_ls00 = CONST_CAST(SAPDB_Char*, DatExtrStmt.CharPtr());
    
    // initialize the answer string
    pSvrCmd->cmdRpyDat_ls00 = new char[MAX_REPLY_LENGTH_LS00];
    memset(pSvrCmd->cmdRpyDat_ls00, DEF_BYTE_LS00, MAX_REPLY_LENGTH_LS00);

    // initialize logging behaviour
    pSvrCmd->cmdLogging_ls00  = SAPDB_FALSE;
    pSvrCmd->cmdInternal_ls00 = SAPDB_TRUE;

    // Build a parse tree to be able to compare table names in the command that
    // generated the DATA (the one parsed now) and the command to load the
    // DATA (parameter to this function)
    rc = ls11ParseLoadCommand(pDBInfo, pSvrCmd);

    // Parsed command MUST be a dataextract command
    tls00_TransformationCmd *pDatExtrCmd = REINTERPRET_CAST(tls00_TransformationCmd*, pSvrCmd->cmdScnDat_ls00);

    if (pSvrCmd->cmdScanRC_ls00 != srFctSqlStmt_els00)
    {
        Tools_DynamicUTF8String DatExtrName;
        Tools_DynamicUTF8String DatLoadName;

        if ( true == pDatExtrCmd->trExclude_ls00 )
        {
            pDatLoadCmd->trExclude_ls00 = pDatExtrCmd->trExclude_ls00;
        }

        DatExtrName.Assign(REINTERPRET_CAST(Tools_DynamicUTF8String::ConstPointer,
                                            pDatExtrCmd->trPartSpec_ls00.psTabName_ls00.asCharp()));
        DatLoadName.Assign(REINTERPRET_CAST(Tools_DynamicUTF8String::ConstPointer,
                                            pDatLoadCmd->trPartSpec_ls00.psTabName_ls00.asCharp()));

        if (0 != DatExtrName.Compare( DatLoadName ))
        {
            pMsgObj->ls98Msg(layDataLoad_els98, ErrText, errTableToLoadNotCurrentTable_els98,
                                                         DatLoadName.StrPtr(),
                                                         DatExtrName.StrPtr());
            rc = errTableToLoadNotCurrentTable_els98;
        }
    }
    else
    {
        pMsgObj->ls98Msg(layDataLoad_els98, ErrText, errCheckHeader_els98);
        rc = errCheckHeader_els98;
    }

    if (NULL != pDatExtrCmd)
    {
        ls10FreeTransformation(srFctColExtract_els00, pSvrCmd->cmdScnDat_ls00 );

        if (NULL != pSvrCmd->cmdRpyDat_ls00)
        {
            delete [] pSvrCmd->cmdRpyDat_ls00;
            pSvrCmd->cmdRpyDat_ls00 = NULL;
        }
        if (NULL != pSvrCmd)
        {
            delete pSvrCmd;
            pSvrCmd = NULL;
        }
    }

    return rc;
}// ls20_CheckHeader

/*
  -----------------------------------------------------------------------------
  function:     ls20_InitDatLoadRec
  -----------------------------------------------------------------------------
*/
static tsp00_Int4
ls20_InitDatLoadRec( tls00_DBInfo             *pDBInfo,
                     tls00_TransformationCmd  *pTransformationCmd,
                     tls00_DloadRec           *&pDatLoadRec,
                     tsp00_Addr               ErrText )
{
    ROUTINE_DBG_MEO00 ("ls20_InitDatLoadRec");

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

    //*
    //* performance
    //*
    extern tls00_Performance performance;
    performance.perRequest_ls00        = 0;
    performance.perReceive_ls00        = 0;
    performance.perIO_ls00             = 0;
    performance.perLog_ls00            = 0;

    // table empty|full
    pDatLoadRec->dlrTabEmpty_ls00  = false;
    pDatLoadRec->dlrTabLoaded_ls00 = false;
    //*
    //* all|user
    //*
    pDatLoadRec->dlrTableSwitched_ls00 = true;
    //*
    //* table
    //*
    memset(&pDatLoadRec->dlrTableInfo_ls00  ,0,sizeof(tls00_TableDescription));
    memset(&pDatLoadRec->dlrDataSource_ls00 ,0,sizeof(tls00_DataSource));
    memset(&pDatLoadRec->dlrPattern_ls00    ,0,sizeof(tls00_Pattern ));
    memset(&pDatLoadRec->dlrMetaData_ls00   ,0,sizeof(tls00_MetaData));
    memset(&pDatLoadRec->dlrParseId_ls00    ,0,MAX_PARSEID_LENGTH_LS00 + 1);
    memset(&pDatLoadRec->dlrResultCount_ls00,0,sizeof(csp_rescnt_unknown));
    pDatLoadRec->dlrResultCount_ls00[0] = 0xff;
    pDatLoadRec->dlrPartAttr_ls00.becomes(sp1pa_first_packet);
    pDatLoadRec->dlrMaxRowsPPckt_ls00   = 0;


    // Init code type and code page
    tls00_DataSource *pDataSource = &pDatLoadRec->dlrDataSource_ls00;

    pDataSource->dasCodeType_ls00  = pTransformationCmd->trDataFile_ls00.fsFormat_ls00.ffoCodeType_ls00;
    pDataSource->pdasCodePage_ls00 = new tsp81_CodePage;

    // We have to take into account the encodings of DATA file AND long files;
    // so we'll copy the code page in any case
    SAPDB_memcpy(&pDataSource->pdasCodePage_ls00->map, pDBInfo->dbiSession_ls00.siCodePage_ls00.map, 512);

    // free space management in order interface buffer
    pDatLoadRec->dlrDataPartHandling_ls00.dphRecordNumbers_ls00 = NULL;
    pDatLoadRec->dlrDataPartHandling_ls00.dphRecordSpace_ls00   = NULL;
    pDatLoadRec->dlrDataPartHandling_ls00.dphRecordLength_ls00  = 0;

    // long value information
    memset(&pDatLoadRec->dlrDInfo_ls00,0,sizeof(tls00_LongExecInfo));
    pDatLoadRec->dlrLongColCnt_ls00 = 0;
    pDatLoadRec->dlrpLongDescriptorVector_ls00 = NULL;

    memset(&pDatLoadRec->dlrDataPartHandling_ls00.dphBuffer_ls00, 0, sizeof(tls00_Buffer));

    // records and columns
    pDatLoadRec->dlrRestart_ls00.rstRestartCommRow_ls00 = 0;

    pDatLoadRec->dlrRecordCount_ls00   = 0;
    pDatLoadRec->dlrInsertedRows_ls00  = 0;
    pDatLoadRec->dlrLastCommLine_ls00  = 0;

    //*
    //*  start load with preparation of insert command and getting parameter info
    //*

    if ( pTransformationCmd->trExclude_ls00 == SAPDB_FALSE )
    {
        rc = ls20_ParseInsertStmt(pDBInfo, pTransformationCmd, pDatLoadRec, ErrText);
        if (errOK_els00 != rc)
        {   //!!ErrorHandling
             return rc;
        }
        //*
        //*  initialize file structure of datasource we are later on working with
        //*
        tls00_FileSpec *pInFileSpec = &pTransformationCmd->trDataFile_ls00;

        // formatted format
        if ( true == pInFileSpec->fsFormat_ls00.ffoBinary_ls00 )
        {
            //*
            //* compute length of record in DATA file
            //*
            tsp00_Int4 lByteCount = ls18GetRowLength(pTransformationCmd->trColSpec_ls00,
                                                     pDatLoadRec->dlrTableInfo_ls00,
                                                     pInFileSpec->fsFormat_ls00.ffoBinary_ls00);
            // Try to read a header; it contains information about the record length
            // of one single record in the file;
            // if the header does not exist we use the earlier calculated record length
            if (0 == pInFileSpec->fsFormat_ls00.ffoBytesPerLine_ls00)       // NOHEADER not found in command
            {
                rc = ls30VFReadHeader(*pDatLoadRec->dlrInfile_ls00, pInFileSpec->fsFormat_ls00.ffoBytesPerLine_ls00, ErrText);
                if (errOK_els00 != rc)
                {
                    if (errNoDatafileHeader_ls98 == rc)
                    {
                        pInFileSpec->fsFormat_ls00.ffoBytesPerLine_ls00 = lByteCount;
                        pMsgObj->ls98PrintMessage(layDataLoad_els98, errNoDatafileHeader_ls98,
                                                                     pInFileSpec->fsFormat_ls00.ffoBytesPerLine_ls00);
                        rc = errOK_els00;
                    }
                    // if file read error, stop execution;
                    // if only no header log it and compute length
                }
            }
            // else-zweig is done because the right value is set
        }
        else
        {
            //*
            //* compute length of record in DATA file
            //*
            tsp00_Int4 lByteCount = ls18GetRowLength(pTransformationCmd->trColSpec_ls00,
                                                     pDatLoadRec->dlrTableInfo_ls00,
                                                     //pInFileSpec->fsFormat_ls00.ffoBinary_ls00);
                                                     pInFileSpec->fsFormat_ls00.ffoFormatted_ls00);
            pInFileSpec->fsFormat_ls00.ffoBytesPerLine_ls00 = lByteCount;
        }

        //*
        //*     Init colLongInfo
        //* assigning LONFFILE Info's from command string
        //*
        ls08InitLongFileInfo(&pTransformationCmd->trColSpec_ls00, &pTransformationCmd->trColLongSpec_ls00);

        // check for loading a part of the file only and move to start position
        if ( (errOK_els00 == rc) &&
             (false == pInFileSpec->fsFormat_ls00.ffoCompact_ls00) &&
             (UNDEFINED_LS00 != pInFileSpec->fsExtract_ls00.feStart_ls00.lnuRemainder_ls00) )
        {
            if (ptTable_els00 == pDatLoadRec->dlrPartSpec_ls00.psPartType_ls00)
            {
                tls00_LargeNumber lFilePos;
                lFilePos.lnu2GB_Blocks_ls00 = 0;        // Is of no interest here and ignored by ls30VFMoveToStartPosition

                if (false == pInFileSpec->fsFormat_ls00.ffoBinary_ls00)  // text file
                {
                    lFilePos = pInFileSpec->fsExtract_ls00.feStart_ls00;
                }
                else
                {
                    lFilePos.lnuRemainder_ls00 = pInFileSpec->fsFormat_ls00.ffoBytesPerLine_ls00 *
                                                (pInFileSpec->fsExtract_ls00.feStart_ls00.lnuRemainder_ls00 - 1);
                }

                // PTS 1113205
                 rc = ls30VFMoveToStartPosition(*pDatLoadRec->dlrInfile_ls00, &lFilePos, ErrText);
            }
        }
    } //if ( pTransformationCmd->trExclude_ls00 == SAPDB_FALSE )

    if ( errOK_els00 == rc )
    {
        rc = ls20_InitStreams(pTransformationCmd, ErrText);
    }

    return rc;
}
//  ls20_InitDatLoadRec()

/*
  -----------------------------------------------------------------------------
  function:     ls20_FreeDatLoadRec
  -----------------------------------------------------------------------------
*/
static void
ls20_FreeDatLoadRec( tls00_TransformationCmd *pTransformationCmd, tls00_DloadRec *& pDatLoadRec )
{
    ROUTINE_DBG_MEO00 ("ls20_FreeDatLoadRec");

    //*
    //* performance
    //*
    extern tls00_Performance performance;
    performance.perRequest_ls00       = 0;
    performance.perReceive_ls00       = 0;
    performance.perIO_ls00            = 0;
    performance.perLog_ls00           = 0;

    pDatLoadRec->dlrInsertedRows_ls00 = 0;
    // pDatLoadRec->dlrLRejected_ls00 MUST not be updated here; it's used to count overall
    // rejected lines if processing TL ALL/USER
    pDatLoadRec->dlrLastCommLine_ls00 = 0;

    tls00_TableDescription  &T  = pDatLoadRec->dlrTableInfo_ls00;
    int                     i   = 0;

    // We have to delete only as much values as we have allocated.
    for (i=0; i < T.tdFieldCount_ls00; ++i)
    {
        if (NULL != T.tdParamArray_ls00[i])
        {
            delete T.tdParamArray_ls00[i];
            T.tdParamArray_ls00[i] = NULL;
        }
    }

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

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

    // Delete code page structure
    if (NULL != pDatLoadRec->dlrDataSource_ls00.pdasCodePage_ls00)
    {
        delete pDatLoadRec->dlrDataSource_ls00.pdasCodePage_ls00;
        pDatLoadRec->dlrDataSource_ls00.pdasCodePage_ls00 = NULL;
    }

    // Delete input buffer
    if (NULL != pDatLoadRec->dlrDataSource_ls00.dasInputBuffer.pBufPtr_ls00)
    {
        delete [] STATIC_CAST(unsigned char*, pDatLoadRec->dlrDataSource_ls00.dasInputBuffer.pBufPtr_ls00);
        pDatLoadRec->dlrDataSource_ls00.dasInputBuffer.pBufPtr_ls00 = NULL;
    }

    // Delete converted DATA buffer
    ls18RecordDestructor(pDatLoadRec->dlrTableInfo_ls00.tdFieldCount_ls00, pDatLoadRec->dlrDataSource_ls00.dasConvertedData);

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

    // delete pattern matching structure
    if (NULL != pDatLoadRec->dlrPattern_ls00.ppatPattern_ls00)
    {
        delete [] pDatLoadRec->dlrPattern_ls00.ppatPattern_ls00;
        pDatLoadRec->dlrPattern_ls00.ppatPattern_ls00 = NULL;
    }
    if (NULL != pDatLoadRec->dlrPattern_ls00.plpatFailure_ls00)
    {
        delete [] pDatLoadRec->dlrPattern_ls00.plpatFailure_ls00;
        pDatLoadRec->dlrPattern_ls00.plpatFailure_ls00 = NULL;
    }

    // - close LONG DATA files still open only if the file format is not RECORDS
    // - delete conversion buffers (if allocated)
    tls00_MultColSpec &MultCol = pTransformationCmd->trColSpec_ls00;

    if (0 != pDatLoadRec->dlrLongColCnt_ls00)
    {
        char szErr[256];
        szErr[0] = 0;

        tls00_Column *pCol = NULL;

        for (i = 0; i < MultCol.mcsCount_ls00; ++i)
        {
            pCol = MultCol.mcsColumn_ls00[i];
            if (true == pCol->colLongInfo.loiIsLong_ls00)
            {
                if ( (NULL  != pCol->colLongInfo.loiFileStruct_ls00) &&
                     (false == pTransformationCmd->trDataFile_ls00.fsFormat_ls00.ffoCompact_ls00) )
                {
                    ls30VFClose(*pCol->colLongInfo.loiFileStruct_ls00, szErr);
                }
            }
        }

        if (NULL != pDatLoadRec->dlrDInfo_ls00.dliConversionBuffer_ls00.pBufPtr_ls00)
        {
            delete [] (STATIC_CAST(unsigned char*, pDatLoadRec->dlrDInfo_ls00.dliConversionBuffer_ls00.pBufPtr_ls00));
            pDatLoadRec->dlrDInfo_ls00.dliConversionBuffer_ls00.pBufPtr_ls00 = NULL;
            pDatLoadRec->dlrDInfo_ls00.dliConversionBuffer_ls00.lBufLen_ls00 = 0;
        }

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

        if (NULL != pDatLoadRec->dlrpLongDescriptorVector_ls00)
        {
            delete [] pDatLoadRec->dlrpLongDescriptorVector_ls00;
            pDatLoadRec->dlrpLongDescriptorVector_ls00 = NULL;
        }
    }

    // allocated buffer for DATA
    if (NULL != pDatLoadRec->dlrDataPartHandling_ls00.dphBuffer_ls00.pBufPtr_ls00)
    {
        delete [] (STATIC_CAST(unsigned char*, pDatLoadRec->dlrDataPartHandling_ls00.dphBuffer_ls00.pBufPtr_ls00));
        pDatLoadRec->dlrDataPartHandling_ls00.dphBuffer_ls00.pBufPtr_ls00 = NULL;
    }
}
//  ls20_FreeDatLoadRec()

/*
  -----------------------------------------------------------------------------
  function: ls20_InitStreams
  -----------------------------------------------------------------------------
*/
static tsp00_Int4
ls20_InitStreams(tls00_TransformationCmd* pTransformationCmd, tsp00_Addr pszErrText)
{
    ROUTINE_DBG_MEO00 ("ls20_InitStreams");
    tsp00_Int4 rc = errOK_els00;

    //*
    //*   long file
    //*
    if (0 != pTransformationCmd->trColLongSpec_ls00.mfsCount_ls00)
    {
        // We can only initialize long file at this time if they have been specified
        // in the command
        rc = ls20_InitAndOpenLongFiles(&pTransformationCmd->trColSpec_ls00, pszErrText);
    }

    return rc;
}
//ls20_InitStreams()


/*
  -----------------------------------------------------------------------------
  function:     ls20_InitAndOpenLongFiles
  -----------------------------------------------------------------------------
*/
static tsp00_Int4
ls20_InitAndOpenLongFiles(tls00_MultColSpec  *pMultCol,
                          tsp00_Addr          ErrText)
{
    ROUTINE_DBG_MEO00 ("ls20_InitAndOpenLongFiles");

    tsp00_Int4 rc = errOK_els00;

    tls00_Column *pCol = NULL;

    for (int i = 0; ( (errOK_els00 == rc) && (i < pMultCol->mcsCount_ls00) ); ++i)
    {
        pCol = pMultCol->mcsColumn_ls00[i];

        if ( pCol->colLongInfo.loiWithLongInfo_ls00 == true )
        {
            pCol->colLongInfo.loiFileStruct_ls00 = new tls00_VFile;
            memset(pCol->colLongInfo.loiFileStruct_ls00, 0, sizeof(tls00_VFile));

            if (  NULL  != pCol->colLongInfo.loiFileStruct_ls00 &&
                  0     == pCol->colLongInfo.loiFileStruct_ls00->vfFileHndl_ls00)
            {
                // init file as binary
                ls30VFInitialize(*pCol->colLongInfo.loiFileStruct_ls00, pCol->colLongInfo.loiLongFileName_ls00,
                                 sp5vf_binary, sp5vf_read, pCol->colLongInfo.loiFileEncoding_ls00);

                rc = ls30VFOpen(*pCol->colLongInfo.loiFileStruct_ls00, ErrText);
                if (errOK_els00 == rc)
                {
                    rc = ls30Detect_BinaryFile_Encoding(*pCol->colLongInfo.loiFileStruct_ls00, ErrText);
                }
            }
        }
    }
    return rc;
}
// ls20_InitAndOpenLongFiles()


/*
  -----------------------------------------------------------------------------
  function:     ls20_ParseInsertStmt
  -----------------------------------------------------------------------------
*/
static tsp00_Int4
ls20_ParseInsertStmt(tls00_DBInfo            *pDBInfo,
                     tls00_TransformationCmd *pTransformationCmd,
                     tls00_DloadRec          *pDatLoadRec,
                     tsp00_Addr              pszErrText)
{
    ROUTINE_DBG_MEO00 ("ls20_ParseInsertStmt");

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

    tls00_MultColSpec      &MultCol   = pTransformationCmd->trColSpec_ls00;
    tls00_TableSpec        &TableSpec = pTransformationCmd->trTable_ls00;
    tls00_TableDescription *pTI       = &pDatLoadRec->dlrTableInfo_ls00;
    tls00_Column*           pColumn       = NULL;

    tsp00_Int4             _lCmdLen = 0;
    bool                   _bAssignments  = false;
    tsp00_Int4             i              = 0;
    tsp00_Uint4            _lPos          = 0;

    //*
    //*     - Check if user specified column names in command; if not get them here
    //*     - Check for assignments in command
    //*
    if (0 == MultCol.mcsCount_ls00)
    {
        if (0 != TableSpec.tsTabOwnr_ls00.length() ||
            0 != TableSpec.tsTabName_ls00.length()    )
            rc = ls13GetColumnNames(pDBInfo, TableSpec.tsFullTabName_ls00, pTI, pszErrText);
        else
            rc = ls13GetColumnNames(pDBInfo, pTransformationCmd->trPartSpec_ls00.psFullTabName_ls00, pTI, pszErrText);

        // No columns specified in command: get'em from db
        if (errOK_els00 != rc)
        {
            return STATIC_CAST(tsp00_Int4, rc);
        }
        else
        {
            // adapt column count
            MultCol.mcsCount_ls00 = pTI->tdFieldCount_ls00;

            // Create structure MultCol
            for (int i=0; i < pTI->tdFieldCount_ls00; i++)
            {
                if (NULL == MultCol.mcsColumn_ls00[i])
                {
                    MultCol.mcsColumn_ls00[i] = new tls00_Column;
                    memset(MultCol.mcsColumn_ls00[i], DEF_BYTE_LS00, sizeof(tls00_Column));
                }
                _tcscpy(MultCol.mcsColumn_ls00[i]->colName_ls00.asCharp(), pTI->tdColName_ls00[i]->asCharp());
            }
        }
    }
    else
    {
        // User specified columns in DATALOAD command 
        // --> assignments are possible; we check for assignments and add their length here already
        for (int j=0, k=0; j < MultCol.mcsCount_ls00; ++j)
        {
            pColumn = MultCol.mcsColumn_ls00[j];

            if (asUnknown_els00 != pColumn->colAssign_ls00.fasAsgnTyp_ls00)
            {
                if (0 != pColumn->colAssign_ls00.fasAsgnLen_ls00)
                {
                    _lCmdLen += pColumn->colAssign_ls00.fasAsgnLen_ls00;
                }
                else
                {
                    _lCmdLen += _tcslen(szDBFunctionNames_ls20[pColumn->colAssign_ls00.fasAsgnTyp_ls00-DBFUNC_NAME_OFFSET_LS20]);
                }
            }
            else
            {
                // Column names are of interest only if those columns must be filled with
                // DATA from DATA file; that doesn't apply for assignments
                pTI->tdColName_ls00[k] = new tsp00_KnlIdentifierc;
                _tcscpy(pTI->tdColName_ls00[k]->asCharp(), pColumn->colName_ls00.asCharp());
                ++k;
            }
        }
        if (_lCmdLen > 0)
        {
            _bAssignments = true;
        }
    }

    //*
    //*     Build INSERT statement and parse it
    //* First time parsing is done as if the user did not specify assignments. This
    //* way the kernel returns information on the columns to handle. This information
    //* is necessary for second time parsing in case of assignments: in case of
    //* literal assignment we have to decide whether to include the DATA in single
    //* quotes or not (depending on whether the columns are number or char columns).
    //* 
    _lCmdLen += (MultCol.mcsCount_ls00 + 12) * sizeof(tsp00_KnlIdentifier);

    char *pszCmd = new char[_lCmdLen];
    pszCmd[0] = '\0';

    if (0 != TableSpec.tsTabOwnr_ls00.length() ||
        0 != TableSpec.tsTabName_ls00.length()    )
    {
        if ( 0 != TableSpec.tsTabOwnr_ls00.length() &&
             0 != TableSpec.tsTabName_ls00.length()    )
            _lPos = sp77sprintf(pszCmd, _lCmdLen, "INSERT INTO \"%s\".\"%s\" (\"%s",
                                                TableSpec.tsTabOwnr_ls00.asCharp(),
                                                TableSpec.tsTabName_ls00.asCharp(),
                                                MultCol.mcsColumn_ls00[0]->colName_ls00.asCharp());
        if ( 0 == TableSpec.tsTabOwnr_ls00.length() &&
             0 != TableSpec.tsTabName_ls00.length()     )
            _lPos = sp77sprintf(pszCmd, _lCmdLen, "INSERT INTO \"%s\" (\"%s", 
                                                TableSpec.tsTabName_ls00.asCharp(),
                                                MultCol.mcsColumn_ls00[0]->colName_ls00.asCharp());
    }
    else
    {
        if ( 0 != pTransformationCmd->trPartSpec_ls00.psTabOwnr_ls00.length() &&
             0 != pTransformationCmd->trPartSpec_ls00.psTabName_ls00.length()    )
             _lPos = sp77sprintf(pszCmd, _lCmdLen, "INSERT INTO \"%s\".\"%s\" (\"%s",
                                                pTransformationCmd->trPartSpec_ls00.psTabOwnr_ls00.asCharp(),
                                                pTransformationCmd->trPartSpec_ls00.psTabName_ls00.asCharp(),
                                                MultCol.mcsColumn_ls00[0]->colName_ls00.asCharp());
        if ( 0 == pTransformationCmd->trPartSpec_ls00.psTabOwnr_ls00.length() &&
             0 != pTransformationCmd->trPartSpec_ls00.psTabName_ls00.length()    )
             _lPos = sp77sprintf(pszCmd, _lCmdLen, "INSERT INTO \"%s\" (\"%s", 
                                                pTransformationCmd->trPartSpec_ls00.psTabName_ls00.asCharp(),
                                                MultCol.mcsColumn_ls00[0]->colName_ls00.asCharp());
    }

    for (i=1; i < MultCol.mcsCount_ls00; i++)
    {
        _lPos += sp77sprintf(pszCmd+_lPos, _lCmdLen-_lPos, "\",\"%s", MultCol.mcsColumn_ls00[i]->colName_ls00.asCharp());
    }
    _lPos += sp77sprintf(pszCmd+_lPos, _lCmdLen-_lPos, "\") VALUES(?");

    // Define pos in statement where value specification starts for later use in case
    // the user specified assignments in command
    size_t _lValueStartPos = _lPos - sizeof(char);

    for (i=1; i < MultCol.mcsCount_ls00; ++i)
    {
        _lPos += sp77sprintf(pszCmd+_lPos, _lCmdLen-_lPos, ",?");
    }
    _lPos += sp77sprintf(pszCmd+_lPos, _lCmdLen-_lPos, ") %s", szDuplicateString[pTransformationCmd->trDplMode_ls00]);

    TRACE_PRNF_MLS99(("ls20_ParseInsertStmt", "Stmt to parse: %s\n", pszCmd) );

    // Let's parse
    rc = ls13Parse(pszCmd, pDBInfo, pDatLoadRec->dlrParseId_ls00, pTI, pszErrText, false, true);
    if ( (errOK_els00 == rc) && (true == _bAssignments) )
    {
        TRACE_PRNF_MLS99(("ls20_ParseInsertStmt", "Assignments in load command; parsing 2nd time\n") );

        //*
        //*     Build INSERT statement a second time and parse again if the user
        //*     specified assignments in command
        //*

        // We have filled
        //                   pTI->tdParamArray_ls00
        // with the first execution of ls13Parse;
        // we'll use it here for literal assignments to decide wether the value has to
        // be included in single quotes or not (DATA type);

        tls00_FieldAsgn* pAssignment = NULL;
        
        pszCmd[_lValueStartPos] = 0;    // reinitialize pszCmd string to the pos where the value spec begins
        _lPos                   = _lValueStartPos;

        for (i=0; i < MultCol.mcsCount_ls00; ++i)
        {
            pAssignment = &MultCol.mcsColumn_ls00[i]->colAssign_ls00;
            
            if (asUnknown_els00 == MultCol.mcsColumn_ls00[i]->colAssign_ls00.fasAsgnTyp_ls00)
            {
                _lPos += sp77sprintf(pszCmd+_lPos, _lCmdLen-_lPos, "?,");
            }
            else
            {
                switch (pAssignment->fasAsgnTyp_ls00)
                {
                    case asLiteral_els00:
                    {
                        if (1 == szMap_NumberDataType_ls00[pTI->tdParamArray_ls00[i]->piBasicInfo_ls00.fbDataType_ls00])
                        {
                            _lPos += sp77sprintf(pszCmd+_lPos, _lCmdLen-_lPos, "%s,", pAssignment->fasAsgnVal_ls00);
                        }
                        else
                        {
                            _lPos += sp77sprintf(pszCmd+_lPos, _lCmdLen-_lPos, "'%s',", pAssignment->fasAsgnVal_ls00);
                        }
                        break;
                    }
                    default:
                    {
                        _lPos += sp77sprintf(pszCmd+_lPos, _lCmdLen-_lPos, 
                                                           "%s,", szDBFunctionNames_ls20[pAssignment->fasAsgnTyp_ls00-DBFUNC_NAME_OFFSET_LS20]);
                    }
                }   // end switch (MultCol.mcsColumn_ls00[i]->colAssign_ls00.fasAsgnTyp_ls00)
            }
        
        }
        _lPos -= sizeof(char);
        _lPos += sp77sprintf(pszCmd+_lPos, _lCmdLen-_lPos, ") %s", szDuplicateString[pTransformationCmd->trDplMode_ls00]);


        // 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 < pTI->tdFieldCount_ls00; ++j)
        {
            if (NULL != pTI->tdParamArray_ls00[j])
            {
                delete pTI->tdParamArray_ls00[j];
                pTI->tdParamArray_ls00[j] = NULL;
            }
        }
        pTI->tdFieldCount_ls00 = 0;

        TRACE_PRNF_MLS99(("ls20_ParseInsertStmt", "Stmt to parse (2nd): %s\n", pszCmd) );

        rc = ls13Parse(pszCmd, pDBInfo, pDatLoadRec->dlrParseId_ls00, pTI, pszErrText, false, true);
    }   // end if ( (errOK_els00 == rc) && (true == _bAssignments) )

    delete [] pszCmd;

    if (errOK_els00 == rc)
    {
        //*
        //*     Define record length
        pDatLoadRec->dlrDataPartHandling_ls00.dphRecordLength_ls00 = ls18GetRecordLength(*pTI, true);

        //*
        //*     Compute max records to send in one packet
        //* Parts resultcount und parseid need to fit into packet too!
        //*
        pDatLoadRec->dlrMaxRowsPPckt_ls00 = ( pDBInfo->dbiPktSize_ls00 -
                                             (BlockHSize_ls00 + PartHSize_ls00 + PartHSize_ls00 +
                                              sizeof(pDatLoadRec->dlrResultCount_ls00) + MAX_PARSEID_LENGTH_LS00 + 16) ) /
                                              pDatLoadRec->dlrDataPartHandling_ls00.dphRecordLength_ls00;

        if(0 == pDatLoadRec->dlrMaxRowsPPckt_ls00)
        {
            pDatLoadRec->dlrMaxRowsPPckt_ls00 = 1;
        }

        TRACE_PRNF_MLS99(("ls20_ParseInsertStmt", "Max count of rows per packet: %d \n", pDatLoadRec->dlrMaxRowsPPckt_ls00) );


        pDatLoadRec->dlrDataPartHandling_ls00.dphRecordNumbers_ls00 = new tsp00_Int4[pDatLoadRec->dlrMaxRowsPPckt_ls00];
        pDatLoadRec->dlrDataPartHandling_ls00.dphRecordSpace_ls00   = new tsp00_Int4[pDatLoadRec->dlrMaxRowsPPckt_ls00];
    }   // end if (errOK_els00 == rc)

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


/*
  -----------------------------------------------------------------------------
  function:     ls20_InitStructures
  -----------------------------------------------------------------------------
*/
static tsp00_Int4
ls20_InitStructures(tls00_DBInfo            *pDBInfo,
                    tls00_TransformationCmd *pTransformationCmd,
                    tls00_DloadRec          *pDatLoadRec,
                    tsp00_Addr               ErrText)
{
    ROUTINE_DBG_MEO00 ("ls20_InitStructures");

    LoaderMessages *pMsgObj = LoaderMessages::Instance();    // error reporting obj
    tsp00_Int4       rc      = errOK_els00;

    tls00_MultColSpec      &MultCol   = pTransformationCmd->trColSpec_ls00;
    tls00_TableDescription &TableInfo = pDatLoadRec->dlrTableInfo_ls00;
    tls00_Column           *pCol      = NULL;
    tls00_ParamInfo_LONG*   pLCI      = NULL;

    //*
    //*     assign table name
    //*
    TableInfo.tdTablename_ls00.Init();
    TableInfo.tdTablename_ls00.rawAssign(pTransformationCmd->trTable_ls00.tsTabName_ls00.asCharp());

    //*
    //*     NULL value representation
    //* Check and convert. We assume the loader runs on ascii.
    //*
    if (NULL != pTransformationCmd->trTable_ls00.tsCondSpec_ls00)
    {
        rc = ls16ConvertCondition(*pTransformationCmd->trTable_ls00.tsCondSpec_ls00,
                                  pDBInfo->dbiOwnSwap_ls00,
                                  pTransformationCmd->trDataFile_ls00.fsFormat_ls00,
                                  ErrText);
    }

    // Now allocate space and initialize DATA source structure
    if (errOK_els00 == rc)
    {
        // Initialization - a hack
        pDatLoadRec->dlrDataSource_ls00.dasInputBuffer.lBufLen_ls00 = 6 * pDBInfo->dbiPageSize_ls00;

        ls20InitDataSourceStruct(&pDatLoadRec->dlrDataSource_ls00,
                                 &pTransformationCmd->trDataFile_ls00.fsFormat_ls00,
                                 TableInfo.tdFieldCount_ls00,
                                 &MultCol,
                                 0);

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


    //*
    //*     Check for column conditions      and
    //*     Set special abstract types       and
    //*     Adapt LONG value specifications  and
    //*     Adapt fraction value: if UNDEFINED_LS00 we take the db value.
    //*
    tsp00_Int4         i   = 0;
    tls00_FieldBasics *pBI = NULL;

    for (i; ( (errOK_els00 == rc) && (i < TableInfo.tdFieldCount_ls00) ); ++i)
    {
        pCol = MultCol.mcsColumn_ls00[pDatLoadRec->dlrDataSource_ls00.plDataToColIndex_ls00[i]];
        pBI  = &TableInfo.tdParamArray_ls00[i]->piBasicInfo_ls00;

        //* Check for needs of transformation of NULL value representation for DEFAULT NULL
        //* specification (mainly in case DATA file encoding is UCS2 in any form).
        if (NULL != pCol->colNullCond_ls00)
        {
            rc = ls16ConvertCondition(*pCol->colNullCond_ls00,
                                      pDBInfo->dbiOwnSwap_ls00,
                                      pTransformationCmd->trDataFile_ls00.fsFormat_ls00,
                                      ErrText);
        }

        if ( (errOK_els00 == rc) && (UNDEFINED_LS00 == pCol->colFormat_ls00.ffoFrac_ls00) )
        {
            pCol->colFormat_ls00.ffoFrac_ls00 = pBI->fbFraction_ls00;
        }

        //*
        //*     LONG columns
        //*
        if ( (errOK_els00 == rc) && (1 == szMap_LongDataType_ls00[pBI->fbDataType_ls00]) )
        {
            pLCI = &pCol->colLongInfo;

            pLCI->loiIsLong_ls00 = true;

            if (true == pTransformationCmd->trDataFile_ls00.fsFormat_ls00.ffoCompact_ls00)
            {
                pLCI->loiFileStruct_ls00 = pDatLoadRec->dlrInfile_ls00;
                // Define file encoding
                pLCI->loiFileStruct_ls00->vfFileEncoding_ls00 = pTransformationCmd->trDataFile_ls00.fsFormat_ls00.ffoCodeType_ls00;

                // This is done because the file in format RECORDS is opened as binary file but it
                // is not marked as encoded at the very beginning. Because the data file stores 'normal'
                // data and LONG data we have to ensure that no magic bytes will be requested when
                // processing LONGs
                ls30VFEmptyMagicBytesCache(pLCI->loiFileStruct_ls00, true);
            }
            else //if (false == pDatLoadCmd->dloInfile_ls00.fsFormat_ls00.ffoCompact_ls00)
            {
//TODOTODO Besser in init_and_open_Longfile machen!??!?!??!
                if (NULL == pLCI->loiFileStruct_ls00)
                {
                    pCol->colLongInfo.loiFileStruct_ls00 = new tls00_VFile;
                    memset(pCol->colLongInfo.loiFileStruct_ls00, 0, sizeof(tls00_VFile));
                }
                else
                {
                    // Check compatibility of external code type to db data type
                    rc = ls08CheckLONG_DT_Compatibility(pLCI->loiFileStruct_ls00->vfFileEncoding_ls00, pBI->fbDataType_ls00);
                    if (errOK_els00 != rc)
                    {
                        // error: data types do not match (function returns only ok or errIncompatibleDataTypes_els98)
                        pMsgObj->ls98Msg(layDataLoad_els98, ErrText, errIncompatibleDataTypes_els98,
                                                                     TableInfo.tdColName_ls00[i]->asCharp() );
                        break;
                    }
                }
            }   // end else of if (true == pDatLoadCmd->dloInfile_ls00.fsFormat_ls00.ffoCompact_ls00)

            ++pDatLoadRec->dlrLongColCnt_ls00;
        } // end if ( (errOK_els00 == rc) && (1 == szMap_LongDataType_ls00[pBI->fbDataType_ls00]) )
    }   // end for (i; ( (errOK_els00 == rc) && (i < TableInfo.tdFieldCount_ls00) ); ++i)



    // Initialize variables used for LONG value processing
    //  - vector of long descriptors; used for handling LONGs in putval packets
    //  - array of indexes of NOT NULL LONG values in every single record
    //  - conversion buffer used for conversion of LONGs between different encodings and hex representation
    if ( (errOK_els00 == rc) && (0 != pDatLoadRec->dlrLongColCnt_ls00) )
    {
        pDatLoadRec->dlrpLongDescriptorVector_ls00 = new tsp00_LongDescriptor[pDatLoadRec->dlrLongColCnt_ls00];
        pDatLoadRec->dlrDInfo_ls00.dliNNLongs_ls00 = new tsp00_Int2[pDatLoadRec->dlrLongColCnt_ls00];

        pDatLoadRec->dlrDInfo_ls00.dliConversionBuffer_ls00.lBufLen_ls00 = 8*pDBInfo->dbiPktSize_ls00;
        pDatLoadRec->dlrDInfo_ls00.dliConversionBuffer_ls00.pBufPtr_ls00 =
            new unsigned char[pDatLoadRec->dlrDInfo_ls00.dliConversionBuffer_ls00.lBufLen_ls00];
    }

    return rc;
}
// ls20_InitStructures()

/*!
  -----------------------------------------------------------------------------
  function:     ls20_TransformRowColumns
  -----------------------------------------------------------------------------
*/
static tsp00_Int4
ls20_TransformRowColumns( tls00_TransformationCmd  *pTransformationCmd,
                          tls00_DloadRec    *pDatLoadRec,
                          tsp1_sqlmode_Enum  SQLMode,
                          bool               bUnicodeOI,
                          tsp00_Addr         ErrText)
{
    ROUTINE_DBG_MEO00 ("ls20_TransformRowColumns");

    LoaderMessages *pMsgObj = LoaderMessages::Instance();    // error msg obj
    tsp00_Longint    rc      = errOK_els00;

    tls00_ParamInfo  *pPI     = NULL;
    tls00_FileFormat  Format  = pTransformationCmd->trDataFile_ls00.fsFormat_ls00;
    tls00_Column     *pCol    = NULL;
    tls00_String     *RawData = pDatLoadRec->dlrDataSource_ls00.dasConvertedData;

    tsp00_Addr pszInputLine = STATIC_CAST(char*, pDatLoadRec->dlrDataSource_ls00.dasInputBuffer.pBufPtr_ls00);
    tsp00_Int4 InputLen     = pDatLoadRec->dlrDataSource_ls00.dasInputBuffer.lBufPos_ls00;

    //*
    //*     Read DATA
    //*
    tsp00_Int4 lFailIndex = 0;
    if (true == Format.ffoFormatted_ls00)           // read formatted DATA
    {
        rc = ls18GetFormattedValueEx(pszInputLine,
                                     InputLen,
                                     &pTransformationCmd->trColSpec_ls00,
                                     pDatLoadRec->dlrDataSource_ls00.lReadFieldsCnt_ls00,
                                     pDatLoadRec->dlrDataSource_ls00.plDataToColIndex_ls00,
                                     RawData,
                                     lFailIndex);
    }
    else if (true == Format.ffoCompress_ls00)
    {
        rc = ls18GetCSVData(pszInputLine,
                            InputLen,
                            &pDatLoadRec->dlrPattern_ls00,
                            pDatLoadRec->dlrDataSource_ls00.lReadFieldsCnt_ls00,
                            pDatLoadRec->dlrDataSource_ls00.lReadPos_ls00,
                            pTransformationCmd->trDataFile_ls00.fsFormat_ls00.ffoCodeType_ls00,
                            RawData,
                            lFailIndex);


/* This is actually the right place for this function; still in ls20TransformColumnValue
        if (errOK_els00 == rc)
        {
            for (SAPDB_UInt i = 0; i < pDatLoadRec->dlrDataSource_ls00.lReadFieldsCnt_ls00; ++i)
            {
                pPI  = pDatLoadRec->dlrTableInfo_ls00.tdParamArray_ls00[i];
                pCol = pTransformationCmd->trColSpec_ls00.mcsColumn_ls00[pDatLoadRec->dlrDataSource_ls00.plDataToColIndex_ls00[i]];
                if ( (ioChar_els00 == pCol->colFormat_ls00.ffoFormat_ls00) &&
                     (1            == szMap_CharDataType_ls00[pPI->piBasicInfo_ls00.fbDataType_ls00]) &&
                     (1            != szMap_BlobDataType_ls00[pPI->piBasicInfo_ls00.fbDataType_ls00]) &&
                     (INSERT_EMPTY_VALUE != RawData[i].strLeng_ls00) && (INSERT_NULL != RawData[i].strLeng_ls00) )
                {
                    ls18UndoubleDelimitersInCharData(&RawData[i], &pDatLoadRec->dlrPattern_ls00, Format.ffoCodeType_ls00);
                }
            }

        }
*/
    }
    else if (true == Format.ffoCompact_ls00)
    {
        rc = ls18GetCompactValue(pszInputLine,
                                 &pDatLoadRec->dlrMetaData_ls00,
                                 pDatLoadRec->dlrDataSource_ls00.lReadFieldsCnt_ls00,
                                 pDatLoadRec->dlrDataSource_ls00.lReadPos_ls00,
                                 RawData,
                                 &pTransformationCmd->trColSpec_ls00,
                                 lFailIndex);
    }
    if (errOK_els00 != rc)
    {
        pMsgObj->ls98Msg(layDataLoad_els98, ErrText, errAtRow_els98, pDatLoadRec->dlrRecordCount_ls00);

        if (errMissingData_els98 == rc)
        {
            pMsgObj->ls98Msg(layDataLoad_els98, ErrText, errMissingData_els98,
                                                         pDatLoadRec->dlrTableInfo_ls00.tdColName_ls00[lFailIndex]->asCharp());
        }
    }



    tsp00_Longint len = 0;
    tsp00_Uint4   j   = 0;
    for (j=0; ( (errOK_els00 == rc) && (j < pDatLoadRec->dlrDataSource_ls00.lReadFieldsCnt_ls00) ) ; ++j)
    {
        pPI  = pDatLoadRec->dlrTableInfo_ls00.tdParamArray_ls00[j];
        pCol = pTransformationCmd->trColSpec_ls00.mcsColumn_ls00[pDatLoadRec->dlrDataSource_ls00.plDataToColIndex_ls00[j]];

        rc = ls20TransformColumnValue(&RawData[j],
                                      pCol,
                                      &pDatLoadRec->dlrDataSource_ls00.dasInputBuffer,
                                      pPI,
                                      &pTransformationCmd->trDataFile_ls00,
                                      pDatLoadRec->dlrSwapKind_ls00,
                                      SQLMode,
                                      &pDatLoadRec->dlrPattern_ls00,
                                      ErrText);
        if (errOK_els00 != rc)
        {
            pMsgObj->ls98PrintMessage(layDataLoad_els98, errAtRow_els98, pDatLoadRec->dlrRecordCount_ls00);
            pMsgObj->ls98EFromRcToFile(layDataLoad_els98, ErrText, STATIC_CAST(ErrorNumbers, rc));
        }
    }   //  end for (j=0; ( (errOK_els00 == rc) && (j < pDatLoadRec->dlrDataSource_ls00.lReadFieldsCnt_ls00) ) ; ++j)

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


/*
  -----------------------------------------------------------------------------
  function:     ls20_TransformTableRows
  -----------------------------------------------------------------------------
*/
static tsp00_Int4
ls20_TransformTableRows(tls00_DBInfo     *pDBInfo,
                        tls00_TransformationCmd *pTransformationCmd,
                        tls00_DloadRec   *pDatLoadRec,
                        bool              bRecoverLong,
                        tsp00_Addr        ErrText,
                        tsp00_Int4       &RowCount,
                        bool             &bPutVal)
{
    ROUTINE_DBG_MEO00 ("ls20_TransformTableRows");

    tsp00_Longint rc     = errOK_els00;
    tsp00_Int4    rcREAD = errOK_els00;

    pDatLoadRec->dlrPartAttr_ls00.becomes(sp1pa_next_packet);

    tsp00_Int4    iRow            = RowCount;
    tls00_String  DataRecord;     // char buffer for reading row in file
    DataRecord.strAddr_ls00 = STATIC_CAST(char*, pDatLoadRec->dlrDataSource_ls00.dasInputBuffer.pBufPtr_ls00);


    tls00_String *RawData         = pDatLoadRec->dlrDataSource_ls00.dasConvertedData;
    tls00_Buffer *pDataPartBuffer = &pDatLoadRec->dlrDataPartHandling_ls00.dphBuffer_ls00;

    bool bUnicodeOI = ls00UseUnicodeOI(pDBInfo);


    // Check if there are some long values to insert before continuing (may happen if some
    // records could not be inserted and bPutVal was set to true
    if (true == bRecoverLong)
    {
        // LONGs? Insert them here. Last inserted 'normal' record is the one for
        // which we have to import the LONG
        rc = ls08InsertLongs(pDatLoadRec->dlrDataPartHandling_ls00,
                             pDatLoadRec->dlrDInfo_ls00,
                             pTransformationCmd->trColSpec_ls00,
                             pDatLoadRec->dlrTableInfo_ls00,
                             pDatLoadRec->dlrDataSource_ls00,
                             bPutVal,
                             bUnicodeOI,
                             ErrText);
        if (errOK_els00 == rc)
        {
            // save used space value for THIS record;
            // (iRow - 1) because iRow gives the number of rows handled up to this point; this must
            // be subtracted by 1 to come to the right index
            pDatLoadRec->dlrDataPartHandling_ls00.dphRecordSpace_ls00[iRow-1] = STATIC_CAST(tsp00_Int4, pDataPartBuffer->lBufLen_ls00);
        }
        else
        {   // Error --> undo inserted record by restoring used space of previous record

            // At this point we might have added already some part of the LONG restoring to the packet;
            // We need to remove all: the record and the long DATA
            pDataPartBuffer->lBufSize_ls00 += (pDatLoadRec->dlrDataPartHandling_ls00.dphRecordSpace_ls00[iRow-1] -
                                                pDatLoadRec->dlrDataPartHandling_ls00.dphRecordSpace_ls00[iRow-2]);
            pDataPartBuffer->lBufLen_ls00  -= (pDatLoadRec->dlrDataPartHandling_ls00.dphRecordSpace_ls00[iRow-1] -
                                                pDatLoadRec->dlrDataPartHandling_ls00.dphRecordSpace_ls00[iRow-2]);
        }

        bRecoverLong = false;
    }

    // Get the records for one request
    for (   iRow;
         ( (iRow < pDatLoadRec->dlrMaxRowsPPckt_ls00)                 &&
           (pDataPartBuffer->lBufSize_ls00 >= pDatLoadRec->dlrDataPartHandling_ls00.dphRecordLength_ls00)  &&
           (errOK_els00 == rcREAD) && (errOK_els00 == rc)             &&
           (false == bPutVal) );
            ++iRow)
    {
        //*
        //*   process single record
        //*

        // get DATA from file

        rcREAD = ls20ReadData(pDatLoadRec->dlrInfile_ls00,
                              &pTransformationCmd->trDataFile_ls00.fsFormat_ls00,
                              &pDatLoadRec->dlrPattern_ls00,
                              &pDatLoadRec->dlrMetaData_ls00,
                              &pDatLoadRec->dlrDataSource_ls00.dasInputBuffer,
                              &pDatLoadRec->dlrTabLoaded_ls00,
                              ( 0 == pDatLoadRec->dlrRecordCount_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;
            }
            else if (STOP_NOMORE_DATA_LS00 == rcREAD)
            {
                --iRow;
            }

            pDatLoadRec->dlrPartAttr_ls00.becomes(sp1pa_last_packet);  // Last DATA in any case
        }
        //*
        //*   check for load condition for table
        //*
        if ( (errOK_els00 == rc) && (STOP_NOMORE_DATA_LS00 != rcREAD) )
        {
            if (NULL != pTransformationCmd->trTable_ls00.tsCondSpec_ls00)
            {
                DataRecord.strLeng_ls00 = pDatLoadRec->dlrDataSource_ls00.dasInputBuffer.lBufPos_ls00;

                if ( false == ls16CheckCondition(*pTransformationCmd->trTable_ls00.tsCondSpec_ls00,
                                                 DataRecord,
                                                 pTransformationCmd->trDataFile_ls00.fsFormat_ls00) )
                {
                    --iRow;
                    continue;
                }
            }
        }

        if ( (errOK_els00 == rc) && (STOP_NOMORE_DATA_LS00 != rcREAD) )
        {
            pDatLoadRec->dlrRecordCount_ls00++;

            //  insert record into RawData structure
            rc = ls20_TransformRowColumns(pTransformationCmd,
                                          pDatLoadRec,
                                          pDBInfo->dbiSession_ls00.siSQLMode_ls00,
                                          bUnicodeOI,
                                          ErrText);
        }

        if ( (errOK_els00 == rc) && (STOP_NOMORE_DATA_LS00 != rcREAD) )
        {
            //*
            //* Save build record number for later error messages
            //*

            pDatLoadRec->dlrDataPartHandling_ls00.dphRecordNumbers_ls00[iRow] = pDatLoadRec->dlrRecordCount_ls00;

            //*
            //* set LONG value descriptions
            //*
            pDatLoadRec->dlrDInfo_ls00.dliCntNNLongs_ls00      = 0;
            pDatLoadRec->dlrDInfo_ls00.dliFinishedNNLongs_ls00 = 0;

            rc = ls20BuildRecord(&pDatLoadRec->dlrDataSource_ls00,
                                 &pDatLoadRec->dlrDataPartHandling_ls00.dphBuffer_ls00,
                                 &pDatLoadRec->dlrTableInfo_ls00,
                                 &pTransformationCmd->trColSpec_ls00,
                                 &pDatLoadRec->dlrDInfo_ls00,
                                 bUnicodeOI,
                                 pDatLoadRec->dlrRecordCount_ls00,
                                 ErrText);
            if (errOK_els00 == rc)
            {
                // adapt free and used space in buffer
                pDataPartBuffer->lBufSize_ls00 -= pDatLoadRec->dlrDataPartHandling_ls00.dphRecordLength_ls00;
                pDataPartBuffer->lBufLen_ls00  += pDatLoadRec->dlrDataPartHandling_ls00.dphRecordLength_ls00;

                if (0 != pDatLoadRec->dlrDInfo_ls00.dliCntNNLongs_ls00)
                {
                    // LONGs? Insert them here. Last inserted 'normal' record is the one for
                    // which we have to import the LONG
                    rc = ls08InsertLongs(pDatLoadRec->dlrDataPartHandling_ls00,
                                         pDatLoadRec->dlrDInfo_ls00,
                                         pTransformationCmd->trColSpec_ls00,
                                         pDatLoadRec->dlrTableInfo_ls00,
                                         pDatLoadRec->dlrDataSource_ls00,
                                         bPutVal,
                                         bUnicodeOI,
                                         ErrText);
                    if (errOK_els00 == rc)
                    {
                        // save used space value for THIS record
                        pDatLoadRec->dlrDataPartHandling_ls00.dphRecordSpace_ls00[iRow] = STATIC_CAST(tsp00_Int4, pDataPartBuffer->lBufLen_ls00);
                    }
                    else
                    {   // Error --> undo inserted record by restoring used space of previous record
                        pDataPartBuffer->lBufSize_ls00 += pDatLoadRec->dlrDataPartHandling_ls00.dphRecordLength_ls00;
                        pDataPartBuffer->lBufLen_ls00  -= pDatLoadRec->dlrDataPartHandling_ls00.dphRecordLength_ls00;
                    }
                }
                else
                {
                    // save used space value for THIS record
                    pDatLoadRec->dlrDataPartHandling_ls00.dphRecordSpace_ls00[iRow] = STATIC_CAST(tsp00_Int4, pDataPartBuffer->lBufLen_ls00);
                }
            }
        }

        // Following if handles errors from GetRecord and BuildRecord. Both functions log the error
        // so we have to adapt the error count only here.
        if (errOK_els00 != rc)
        {
            ++pDatLoadRec->dlrLRejected_ls00;
            if(pDatLoadRec->dlrLRejected_ls00 >= pDBInfo->dbiSession_ls00.siMaxAdmissibleErrors)
            {
                rc = msgTableNotImport_els98;
            }
            else
            {
                rc = errOK_els00;       // reset the error code to read more DATA;
            }

            pDatLoadRec->dlrLastCommLine_ls00 = pDatLoadRec->dlrRecordCount_ls00 - 1;
            --iRow;
        }

        ls18RecordInit(pDatLoadRec->dlrDataSource_ls00.lReadFieldsCnt_ls00,
                       RawData,
                       STATIC_CAST(char*, pDatLoadRec->dlrDataSource_ls00.dasInputBuffer.pBufPtr_ls00),
                       pDatLoadRec->dlrDataSource_ls00.dasInputBuffer.lBufLen_ls00);

    } // END OF FOR count_of_rows

    RowCount = iRow;

    if ( (errOK_els00 == rc) && (STOP_NOMORE_DATA_LS00 == rcREAD) )
    {
        rc = rcREAD;
    }

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


/*!
  -----------------------------------------------------------------------------
  function:     ls20_LoadRowColumns
  -----------------------------------------------------------------------------
*/
static tsp00_Int4
ls20_LoadRowColumns(tls00_DBInfo             *pDBInfo,
                    MetaDataDef              *&pMetaDataDef,
                    tls00_TransformationCmd  *pTransformationCmd,
                    tls00_DloadRec           *pDatLoadRec,
                    tls00_String             &pOI_InitBlock,
                    tsp00_Addr               ErrText)
{
    ROUTINE_DBG_MEO00 ("ls20_LoadRowColumns");

    LoaderMessages *pMsgObj = LoaderMessages::Instance();

    tsp00_Int4 rc       = errOK_els00;
    tsp00_Int4 rcINSERT = errOK_els00;
    tsp00_Int4 rcMETA   = errOK_els00; // Additional return code for handling updates of meta DATA (transformation tables)

    tsp1_packet   *SqlPacket = NULL;
    tsp1_part     *DataPart  = NULL;

    tsp00_Longint  lRestartCount       = 0;

    // define max count of rows to send before sending commit
    tsp00_Longint  lCommitCount        = 0;
    tsp00_Int4     lRowCntBeforeCommit = (0 == pDBInfo->dbiSession_ls00.siTASize_ls00) ?
                                          (10*pDatLoadRec->dlrMaxRowsPPckt_ls00) :
                                          pDBInfo->dbiSession_ls00.siTASize_ls00;

    // We now use pDatLoadRec->dlrMaxRowsPPckt_ls00 as a variable to ls20_TransformTableRows
    if ( (0 != pDBInfo->dbiSession_ls00.siTASize_ls00) &&
         (pDBInfo->dbiSession_ls00.siTASize_ls00 < pDatLoadRec->dlrMaxRowsPPckt_ls00) )
    {
        pDatLoadRec->dlrMaxRowsPPckt_ls00 = pDBInfo->dbiSession_ls00.siTASize_ls00;
    }

    tsp00_Int4              MaxRowsInPacket = pDatLoadRec->dlrMaxRowsPPckt_ls00; // to memorize the value for later user
    tls00_DataPartHandling* pHandling       = &pDatLoadRec->dlrDataPartHandling_ls00;
    tls00_Buffer*           pDataBuffer     = &pHandling->dphBuffer_ls00;
    bool                    bPutVal         = false;
    bool                    bRecoverLong    = false;
    tsp00_Int4              RowCount        =  0;
    tsp00_Int4              tmpRowCnt       = 0;
    char                    szErr[MAX_REPLY_LENGTH_LS00];
    szErr[0] = 0;

    //*
    //*   main loop to load DATA
    //*
    do // while ( errOK_els00 == rc && errOK_els00 == rcINSERT );
    {
        //*
        //* Check RowCount from processing DATA:
        //* RowCount is either MaxRowsInPacket (initialized/reinitialized) or
        //* has a lower value (when called ls20Recover)
        //*
        //* The count of rows used in call to ls20_TransformTableRows depends on 2 values:
        //* 1. overall count of rows to insert set by customer using START option in DATALOAD command
        //* 2. count of rows that can be send using 1 order interface packet
        //*
        if ( (UNDEFINED_LS00 != pTransformationCmd->trDataFile_ls00.fsExtract_ls00.feEnd_ls00.lnuRemainder_ls00) && (0 == RowCount) )
        {
            tsp00_Int4 lDifference = STATIC_CAST(tsp00_Int4, (pTransformationCmd->trDataFile_ls00.fsExtract_ls00.feEnd_ls00.lnuRemainder_ls00 -
                                      (pDatLoadRec->dlrLRejected_ls00 + pDatLoadRec->dlrInsertedRows_ls00)) );
            // Check if count of rows to insert is already reached
            if (lDifference > 0)
            {
                if (lDifference < MaxRowsInPacket)
                {
                    pDatLoadRec->dlrMaxRowsPPckt_ls00 = lDifference;
                }
                else
                {
                    pDatLoadRec->dlrMaxRowsPPckt_ls00 = MaxRowsInPacket;
                }
            }
            else // if (lDifference >= 0)       gt should not happen
            {
                rcINSERT = STOP_NOMORE_DATA_LS00;
            }
        }

        //*
        //* Insert DATA into buffer
        //*
        if ( (errOK_els00 == rcINSERT) && (errOK_els00 == rc) )
        {
            rcINSERT = ls20_TransformTableRows(pDBInfo, pTransformationCmd, pDatLoadRec, bRecoverLong, ErrText, RowCount, bPutVal);
            if ( (errOK_els00 != rcINSERT) && (STOP_NOMORE_DATA_LS00 != rcINSERT) )
            {
                rc = rcINSERT;
            }
        }

        if ( (0 == RowCount) && (errOK_els00 == rc) )
        {
            rcINSERT = STOP_NO_DATA_LS00;
        }

        //*
        //* Insert DATA into packet : Everything went fine
        //*
        if ( (errOK_els00 == rcINSERT) || (STOP_NOMORE_DATA_LS00 == rcINSERT) )
        {
            //*
            //*     Before sending the stuff to the kernel we check for cancel request
            //*
            if (errOK_els00 == rc)
            {
                rc = ls01CheckForCancel(pDBInfo->dbiSession_ls00.sipCancelByte_ls00);
                if (errOK_els00 != rc)
                {
                    LoaderMessages::Instance()->ls98Msg(layDataLoad_els98, ErrText, errCancelRequest_els98);
                    break;
                }
            }

            do
            {
                // First we copy initialized packet block to right place in packet
                SqlPacket = pDBInfo->dbiPktSndList_ls00[0];
                SAPDB_memcpy((char*) &SqlPacket->sp1_header, pOI_InitBlock.strAddr_ls00, pOI_InitBlock.strLeng_ls00);

                // Get pointer to DATA part to work with
                ls04GetPart(SqlPacket, sp1pk_data, DataPart);

                // Set part attribute to current value (either nextpacket or lastpacket)
                ls04SetPartAttribute(DataPart, pDatLoadRec->dlrPartAttr_ls00);

                DataPart->sp1p_arg_count() = RowCount;                  // insert count of records in packet

                ls04AddPartAttribute(DataPart, pDatLoadRec->dlrPartAttr_ls00);

                rc = ls04BufToPart(DataPart, REINTERPRET_CAST(char*, pDataBuffer->pBufPtr_ls00), STATIC_CAST(tsp00_Int4, pDataBuffer->lBufLen_ls00));
                if (errOK_els00 == rc)
                {
                    rc = ls04FinishPart (SqlPacket, DataPart);          // finish packet
                }

                if (errOK_els00 == rc)
                {
                    tmpRowCnt = RowCount;       // temp var used for error handling at putval

                    //*
                    //*     Send and receive and handle error in SQL packet
                    //*
                    szErr[0] = 0;
                    tsp00_Int4 lErrorPos = -1;                  // initialize to impossible error position
                    rc = ls03ProcessSQLPacket(pDBInfo, 0, lErrorPos, szErr);
                    if (errOK_els00 == rc)
                    {
                        // reporting
                        pDatLoadRec->dlrInsertedRows_ls00 += RowCount;
                        pDatLoadRec->dlrLastCommLine_ls00  = pHandling->dphRecordNumbers_ls00[RowCount - 1];

                        // reinitializing
                        pDataBuffer->lBufSize_ls00 = pDataBuffer->lBufLen_ls00 + pDataBuffer->lBufSize_ls00;
                        pDataBuffer->lBufLen_ls00  = 0;
                        RowCount = 0;
                    }
                    else
                    {
                        // In case the error position (lErrRecordNo) is not adapted but an error reported
                        // the error happened sending and/or receiving the packet and we stop at this point
//TODOTODO                      if (-1 == lErrorPos)
                        if (-1 != lErrorPos )
                        {
                            if (ptTable_els00 == pDatLoadRec->dlrPartSpec_ls00.psPartType_ls00)
                            {
                                pMsgObj->ls98PrintMessage(layDataLoad_els98, errAtRow_els98, pHandling->dphRecordNumbers_ls00[lErrorPos - 1]);
                            }
                            else
                            {
                                pMsgObj->ls98PrintMessage(layDataLoad_els98, errAtRowWithTabname_els98,
                                                                             pHandling->dphRecordNumbers_ls00[lErrorPos - 1],
                                                                             pTransformationCmd->trPartSpec_ls00.psTabName_ls00.asCharp());
                            }
                            pMsgObj->ls98Msg(layDataLoad_els98, ErrText, errSimpleSQL_els98, szErr);

                            // Set error code
                            rc = errSimpleSQL_els98;

                            ++pDatLoadRec->dlrLRejected_ls00;               // increase error counter
                            pDatLoadRec->dlrInsertedRows_ls00 += lErrorPos - 1;

                            if (1 != lErrorPos)       // adapt only if not the first record was erroneous
                            {
                                pDatLoadRec->dlrLastCommLine_ls00 = pHandling->dphRecordNumbers_ls00[lErrorPos - 2];
                            }

                            //*
                            //*     Check if user specified number of errors allowed and if we already exceed this number
                            //*
                            if (pDatLoadRec->dlrLRejected_ls00 < pDBInfo->dbiSession_ls00.siMaxAdmissibleErrors)
                            {
                                // Initializes RowCount, too
                                ls20Recover(pHandling,
                                            pDatLoadRec->dlrLongColCnt_ls00,
                                            &pDatLoadRec->dlrTableInfo_ls00,
                                            RowCount,
                                            lErrorPos,
                                            bPutVal);

                                rc       = errOK_els00;
                                ErrText[0] = '\0';

                                // If we have some place in the packet we must recover longs first
                                if (true == bPutVal)
                                {
                                    bRecoverLong = true;
                                    bPutVal      = false;
                                }
                            }
                        }
                    }   // end if (errOK_els00 == rc) ... else of rc = ls03ProcessSQLPacket(pDBInfo, 0, lErrorPos, szErr);
                }// end if (errOK_els00 == rc)

            }
            while ( (STOP_NOMORE_DATA_LS00 == rcINSERT) && (RowCount > 0) && (errOK_els00 == rc) );

            //*
            //*     Process remaining LONGs using putval
            //* RowCount is set to 0 if there was no error in the DATA
            //*
            if ( (errOK_els00 == rc) && (true == bPutVal) )
            {
                rc = ls08ExecPutVal(*pDataBuffer,
                                    pDBInfo,
                                    pDatLoadRec->dlrDInfo_ls00,
                                    pDatLoadRec->dlrpLongDescriptorVector_ls00,
                                    pTransformationCmd->trColSpec_ls00,
                                    pDatLoadRec->dlrPartAttr_ls00,
                                    pDatLoadRec->dlrTableInfo_ls00,
                                    pDatLoadRec->dlrDataSource_ls00.pdasCodePage_ls00,
                                    ErrText);
                if (errOK_els00 != rc)
                {
                    ++pDatLoadRec->dlrLRejected_ls00;
                    --pDatLoadRec->dlrInsertedRows_ls00;
                    pDatLoadRec->dlrLastCommLine_ls00 = pHandling->dphRecordNumbers_ls00[tmpRowCnt - 2];

                    pMsgObj->ls98Msg(layDataLoad_els98, ErrText, errAtRow_els98,
                                                                 pHandling->dphRecordNumbers_ls00[tmpRowCnt - 1]);
                    if(pDatLoadRec->dlrLRejected_ls00 >= pDBInfo->dbiSession_ls00.siMaxAdmissibleErrors)
                    {
                        rc = msgTableNotImport_els98;
                    }
                    else
                    {
                        ErrText[0] = '\0';
                    }
                }
                bPutVal = false;    // reinitialize
            }
            rcMETA = errOK_els00;

            // commit in any case
            tsp00_Longint tmpCnt = pDatLoadRec->dlrInsertedRows_ls00 / lRowCntBeforeCommit;

            if ( tmpCnt > lCommitCount )
            {
                lCommitCount = tmpCnt;

                rcMETA = ls15RSCommit(pDBInfo, ErrText);
                if (errOK_els00 == rcMETA)
                {
                    //*
                    //*     The following commit assures restart ability because we have one
                    //*     single transaction for updating the meta DATA and for inserting the DATA;
                    //*     for internal commands the autocommit is always off
                    //*
                    rcMETA = ls20UpdateTransformationPackage(pDBInfo, pMetaDataDef, pTransformationCmd, pDatLoadRec, ErrText);

                    TRACE_PRNF_MLS99(("ls20_LoadRowColumns", "Commit after %d rows\n", pDatLoadRec->dlrLastCommLine_ls00) );
                }
                else
                {
                    pMsgObj->ls98Msg(layDataLoad_els98, ErrText, errInternal_els98, __FILE__, __LINE__, rc );
                    rcMETA = errInternal_els98;
                }
            }

           if ( (errOK_els00 == rc) && (errOK_els00 == rcMETA) && (true == pDatLoadRec->dlrTabLoaded_ls00) )
            {
                pDatLoadRec->dlrLastCommLine_ls00 = pDatLoadRec->dlrInsertedRows_ls00;

                // The following update 'closes' the whole table insert process and
                // is definitely different than the one above
                rcMETA = ls15RSCommit(pDBInfo, ErrText);
                if (errOK_els00 == rc )
                {
                    // See explanation above for atomic transaction of meta DATA and DATA
                    rcMETA = ls20UpdateTransformationPackage(pDBInfo, pMetaDataDef, pTransformationCmd, pDatLoadRec, ErrText);

                    TRACE_PRNF_MLS99(("ls20_LoadRowColumns", "Commit after %d rows\n", pDatLoadRec->dlrLastCommLine_ls00) );
                }
                else
                {
                    pMsgObj->ls98Msg(layDataLoad_els98, ErrText, errInternal_els98, __FILE__, __LINE__, rc );
                    rcMETA = errInternal_els98;
                }

                // Check again for errors while commiting metadata/DATA
                if (errOK_els00 != rcMETA)
                {
                    rc = rcMETA;
                }
            }
        }// end if ( (errOK_els00 == rcINSERT) || (STOP_NOMORE_DATA_LS00 == rcINSERT) )
    }
    while ( errOK_els00 == rc && errOK_els00 == rcINSERT );


    // send again an commit (even if errors occurred)
    ls15RSCommit(pDBInfo, ErrText);
    return rc;
}
//  ls20_LoadRowColumns()

/*===========================================================================*
 *     END
 *===========================================================================*/
