/*



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





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

  module: vin29.cpp

  -----------------------------------------------------------------------------

  responsible:  BerndV

  special area: DBMServer - Kernel Interface

  description:  handling of the kernel interface

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

/*
  -----------------------------------------------------------------------------
  includes
  -----------------------------------------------------------------------------
*/
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
#include <stdio.h>

#include "heo02.h"
#include "heo03.h"
#include "hsp26.h"
#include "hsp100.h"
#include "hsp77.h"
#include "SAPDBCommon/SAPDB_UTF8Basis.hpp"
#include "hin29.h"

/*
  -----------------------------------------------------------------------------
  private macros
  -----------------------------------------------------------------------------
*/
#if COMPILEMODE_MSP00 >= QUICK_MSP00
  // quick fix for PTS 1104718
  #define ASSERT_DBG(cond)        ((cond) ? (void) 0 : \
              sqlk_assert (assertionFailed_esp00, __LINE__, __FILE__, #cond))
#else

  #define ASSERT_DBG(cond)        0

#endif

#define SQLTRACE (session->tracer)

#define IS_UNICODE(session) ((session->code_type == csp_unicode)||(session->code_type == csp_unicode_swap))

#define EMPTYSET_MIN01                     0
#define M_WARNINGSET(set)               (*(tsp00_Int2*)&set)

#define c_max_try  5

#define cin29_cont_cont "CONTINUE\n"
#define cin29_cont_end  "END     \n"
#define cin29_cont_len  (strlen(cin29_cont_end))
#define cin29_min_len   10
#define cin29_nulltext  "(null)"

#define c_intostr " Into ?"
#define c_intolen 7
#define c_varstr ", ?"
#define c_varlen 3

#define c_connect_len   1000

#define RTEERR_OFFSET   10000

/*
  -----------------------------------------------------------------------------
  extern function declarations
  -----------------------------------------------------------------------------
*/
externPascal int s02applencrypt ( 
       tsp00_Name      & clear_pw,
       tsp00_CryptPw   & crypt_pw );

externPascal int s30klen (
    const void    *buf,
    char           ch,
    int            len);

externPascal void s40glint (
    tsp00_Number    *num,
    tsp00_Int4       pos,
    int            len,
    tsp00_Int4      &dest,
    tsp00_NumError &res);

externPascal void s43pstr (
    tsp00_Number    *num,
    tsp00_Int4       pos,
    int            len,
    int            frac,
    char          *source,
    tsp00_Int4       spos,
    int            slen,
    tsp00_NumError &res);

externPascal void s44egchr (
    void          *buf,
    tsp00_Int4       pos,
    integer        len,
    integer        frac,
    void          *dest,
    tsp00_Int4       dpos,
    integer       &dlen,
    tsp00_DecimalPresentation &decimal,
    tsp00_NumError &res);

externPascal void s45stoi4 (
    tsp00_Int4      *val,
    void          *buf,
    int            pos,
    int            len,
    tsp00_NumError &res);

/*
  -----------------------------------------------------------------------------
  implementation private functions
  -----------------------------------------------------------------------------
*/

/*!
  -----------------------------------------------------------------------------
  function:     memcpyUTF8ToUCS2
  -----------------------------------------------------------------------------

  description:  converts a UTF8-encoded buffer to UCS2-encoding

  -----------------------------------------------------------------------------
 */
static int memcpyUTF8ToUCS2(
    char       * pTarget, 
    const char * pSource, 
    int          nSource, 
    bool         bAddNullByte = false,
    int          nTarget      = 0)
{
/*
  SAPDB_UTF8Basis::UTF8ConstPointer srcBeg  = (SAPDB_UTF8Basis::UTF8ConstPointer) pSource;
  SAPDB_UTF8Basis::UTF8ConstPointer srcEnd  = (SAPDB_UTF8Basis::UTF8ConstPointer) (pSource + nSource);
  SAPDB_UTF8Basis::UTF8ConstPointer srcAt   = NULL;
  SAPDB_UTF8Basis::UCS2Pointer      destBeg = (SAPDB_UTF8Basis::UCS2Pointer)      pTarget;
  SAPDB_UTF8Basis::UCS2ConstPointer destEnd = (SAPDB_UTF8Basis::UCS2Pointer)      (pTarget + (nSource * 2));
  SAPDB_UTF8Basis::UCS2Pointer      destAt  = NULL;

  destEnd = (nTarget > 0) ? (SAPDB_UTF8Basis::UCS2Pointer) (pTarget + nTarget) : destEnd;

  SAPDB_UTF8Basis::ConvertToUCS2 (srcBeg, srcEnd, srcAt, destBeg, destEnd, destAt);

  if (bAddNullByte) {
    pTarget[((char *) destAt) - pTarget]     = 0;
    pTarget[((char *) destAt) - pTarget + 1] = 0;
  } // end if

  return ( ((char *) destAt) - pTarget);
*/
  short swapTest = 1;

  SAPDB_UTF8Basis::UTF8ConstPointer srcBeg  = (SAPDB_UTF8Basis::UTF8ConstPointer) pSource;
  SAPDB_UTF8Basis::UTF8ConstPointer srcEnd  = (SAPDB_UTF8Basis::UTF8ConstPointer) (pSource + nSource);
  SAPDB_UTF8Basis::UTF8ConstPointer srcAt   = NULL;

  tsp81_UCS2Char *                  destBeg = (tsp81_UCS2Char *)                  pTarget;
  tsp81_UCS2Char *                  destEnd = (tsp81_UCS2Char *)                  (pTarget + (nSource * 2));
  tsp81_UCS2Char *                  destAt  = NULL;

  destEnd = (nTarget > 0) ? (tsp81_UCS2Char *) (pTarget + nTarget) : destEnd;

  SAPDB_UTF8Basis::KernelConvertToUTF16(srcBeg, srcEnd, srcAt, destBeg, destEnd, destAt, ((*(char *)&swapTest) ? true : false));

  if (bAddNullByte) {
    pTarget[((char *) destAt) - pTarget]     = 0;
    pTarget[((char *) destAt) - pTarget + 1] = 0;
  } // end if

  return ((int)(((char *) destAt) - pTarget));
} // end memcpyUTF8ToUCS2

/*!
  -----------------------------------------------------------------------------
  function:     memcpyUCS2ToUTF8
  -----------------------------------------------------------------------------

  description:  converts a UCS2-encoded buffer to UTF8-encoding

  -----------------------------------------------------------------------------
 */
static int memcpyUCS2ToUTF8(
    char       * pTarget, 
    const char * pSource, 
    int          nSource, 
    bool         bAddNullByte = false,
    int          nTarget      = 0)
{
/*
  SAPDB_UTF8Basis::UCS2ConstPointer srcBeg  = (SAPDB_UTF8Basis::UCS2ConstPointer) pSource;
  SAPDB_UTF8Basis::UCS2ConstPointer srcEnd  = (SAPDB_UTF8Basis::UCS2ConstPointer) (pSource + nSource);
  SAPDB_UTF8Basis::UCS2ConstPointer srcAt   = NULL;
  SAPDB_UTF8Basis::UTF8Pointer      destBeg = (SAPDB_UTF8Basis::UTF8Pointer)      pTarget;
  SAPDB_UTF8Basis::UTF8ConstPointer destEnd = (SAPDB_UTF8Basis::UTF8ConstPointer) (pTarget + (nSource / 2 * 3));
  SAPDB_UTF8Basis::UTF8Pointer      destAt  = NULL;    

  destEnd = (nTarget > 0) ? (SAPDB_UTF8Basis::UTF8ConstPointer) (pTarget + nTarget) : destEnd;

  SAPDB_UTF8Basis::ConvertFromUCS2(srcBeg, srcEnd, srcAt, destBeg, destEnd, destAt);

  if (bAddNullByte) {
    pTarget[((char *) destAt) - pTarget]     = 0;
  } // end if

  return ( ((char *) destAt) - pTarget);
*/
  short swapTest = 1;

  tsp81_UCS2Char *                  srcBeg  = (tsp81_UCS2Char *)                  pSource;
  tsp81_UCS2Char *                  srcEnd  = (tsp81_UCS2Char *)                  (pSource + nSource);
  tsp81_UCS2Char const *            srcAt   = NULL;
  SAPDB_UTF8Basis::UTF8Pointer      destBeg = (SAPDB_UTF8Basis::UTF8Pointer)      pTarget;
  SAPDB_UTF8Basis::UTF8ConstPointer destEnd = (SAPDB_UTF8Basis::UTF8ConstPointer) (pTarget + (nSource / 2 * 3));
  SAPDB_UTF8Basis::UTF8Pointer      destAt  = NULL;    

  destEnd = (nTarget > 0) ? (SAPDB_UTF8Basis::UTF8ConstPointer) (pTarget + nTarget) : destEnd;

  SAPDB_UTF8Basis::KernelConvertFromUTF16(srcBeg, srcEnd, srcAt, ((*(char *)&swapTest) ? true : false), destBeg, destEnd, destAt);

  if (bAddNullByte) {
    pTarget[((char *) destAt) - pTarget]     = 0;
  } // end if

  return ((int)( ((char *) destAt) - pTarget));
} // end memcpyUCS2ToUTF8

/*!
  -----------------------------------------------------------------------------
  function:     memcpyASCIIToASCII
  -----------------------------------------------------------------------------

  description:  "converts" (copy) a ASCII-encoded buffer to ASCII-encoding

  -----------------------------------------------------------------------------
 */
static int memcpyASCIIToASCII(
    char       * pTarget, 
    const char * pSource, 
    int          nSource, 
    bool         bAddNullByte = false,
    int          nTarget      = 0)
{
  int nSize = (nSource > nTarget && nTarget != 0) ? nTarget : nSource;

  memcpy(pTarget, pSource, nSize);
  if (bAddNullByte)
    pTarget[nSize] = 0;
  return nSize;
} // end memcpyASCIIToASCII

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

static tsp1_segment   *
i29_firstsegment (
    tsp1_packet * packet)
{
    ROUTINE_DBG_MSP00 ("i29_firstsegment");
    return &packet->sp1_segm ();
}

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

static  tsp1_segment   *
i29_nextsegment (
    tsp1_segment * segment)
{
    ROUTINE_DBG_MSP00 ("i29_nextsegment");
    s26next_segment (segment);
    return segment;
}

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

static tsp1_segment   *
i29_lastsegment (
    tsp1_packet * packet)
{
    ROUTINE_DBG_MSP00 ("i29_lastsegment");
    int             segmentCount;
    int             i;
    tsp1_segment   *segment;

    segmentCount = packet->sp1_header.sp1h_no_of_segm;
    segment = i29_firstsegment (packet);
    for (i = 0; i < segmentCount - 1; ++i) {
        segment = i29_nextsegment (segment);
    }
    return segment;
}

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

static tsp1_segment   *
i29_newsegment (
    tin01_sql_session * session,
    tsp1_cmd_mess_type_Enum messType)
{
    ROUTINE_DBG_MSP00 ("i29_newsegment");
    s26first_segment_init (session->send_packet, sp1sk_cmd,
        session->segment);
    session->segment->sp1c_mess_type ().becomes(messType);
    session->segment->sp1c_sqlmode () = tsp1_sqlmode::fromInt (session->sqlMode);
    return session->segment;
}

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

static tin01_bool
i29_findpart (
    tin01_sql_session * session,
    tsp1_part_kind_Enum requiredKind)
{
    ROUTINE_DBG_MSP00 ("i29_findpart");
    /* Find Part return it in session->part */
    if (session->part != NULL) {
        if (session->part->sp1p_part_kind () == requiredKind)
            return true;
    }
    s26find_part (*session->segment, requiredKind, session->part);
    return (session->part != NULL);
} /* i29_findpart */

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

static tin01_bool
i29_findpart (
    tin01_sql_session * session,
    tsp1_part_kind_Enum requiredKind,
    tsp1_part        ** found_part)
{
    ROUTINE_DBG_MSP00 ("i29_findpart");
    /* Find Part without changing session->part */
    if (session->part != NULL) {
        if (session->part->sp1p_part_kind () == requiredKind) {
            *found_part = session->part;
            return true;
        }
    }
    s26find_part (*session->segment, requiredKind, *found_part);
    return (*found_part != NULL);
} /* i29_findpart */

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

static tsp1_part      *
i29_newpart (
    tin01_sql_session * session,
    tsp1_part_kind_Enum partKind)
{
    ROUTINE_DBG_MSP00 ("i29_newpart");
    if (session->segment->sp1s_no_of_parts () > 0)
        s26finish_part (session->send_packet, *session->part);
    s26new_part_init (session->send_packet, *session->segment, session->part);
    ASSERT_DBG (session->part != NULL);
    session->part->sp1p_part_kind ().becomes(partKind);
    return session->part;
}

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

static void
i29_closesend (
    tin01_sql_session * session)
{
    ROUTINE_DBG_MSP00 ("i29_closesend");
    ASSERT_DBG (session->buildingCommand);
    s26finish_part (session->send_packet, *session->part);
    session->send_packet->sp1_header.sp1h_varpart_len = s26packet_len (session->send_packet) -
                                                        sizeof (session->send_packet->sp1_header);
}

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

static void
i29_resetpackets (
    tin01_sql_session * session,
    tin01_bool forCommand)
{
    ROUTINE_DBG_MSP00 ("i29_resetpackets");
    tsp1_packet    *packet;

    session->buildingCommand = forCommand;
    if (forCommand)
        packet = session->send_packet;
    else
        packet = session->rec_packet;
    session->segment = &packet->sp1_segm ();
    if (forCommand) {
        session->part = &session->segment->sp1p_part ();
    }
    else {
        session->part = NULL;
    }
}

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

static void
i29_clearpacketref (
    tin01_sql_session * session)
{
    ROUTINE_DBG_MSP00 ("i29_clearpacketref");
    session->send_packet = NULL;
    session->rec_packet = NULL;
    session->segment = NULL;
    session->part = NULL;
}

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

static int
i29_adabasmode (
    tin01_sql_session * session)
{
    ROUTINE_DBG_MSP00 ("i29_adabasmode");
    int             result;

    result = session->sqlMode;
    session->sqlMode = sp1sm_internal;
    return result;
}

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

static int
i29_oldmode (
    tin01_sql_session * session,
    int oldMode)
{
    ROUTINE_DBG_MSP00 ("i29_oldmode");
    int             result;

    result = session->sqlMode;
    session->sqlMode = oldMode;
    return result;
}

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

static void
i29_reset (
    tin01_sql_session * session,
    tin01_bool initClientInfo)
{
    ROUTINE_DBG_MSP00 ("i29_reset");
    tsp1_packet_header *header;
    /*
     * init packet
     */
    if (!session->buildingCommand)
        i29_resetpackets (session, true);
    header = &session->send_packet->sp1_header;
    if (initClientInfo) {
        header->sp1h_mess_code = session->code_type;
        header->sp1h_mess_swap = session->swap_kind;
        header->sp1h_filler2 = 0;

        memcpy (header->sp1h_appl_version, session->senderid,
            sizeof (session->senderid));
    } // end if
    header->sp1h_filler1 = 0;
    header->sp1h_no_of_segm = 1;
}

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

static void
i29_initadbs (
    tin01_sql_session * session)
{
    ROUTINE_DBG_MSP00 ("i29_initadbs");
    i29_reset (session, true);
    i29_newsegment (session, sp1m_dbs);
    i29_newpart (session, sp1pk_command);
}

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

static void
i29_initparse (
    tin01_sql_session * session)
{
    ROUTINE_DBG_MSP00 ("i29_initparse");
    i29_reset (session, true);
    i29_newsegment (session, sp1m_parse);
    i29_newpart (session, sp1pk_command);
}

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

static void
i29_initexecute (
    tin01_sql_session * session,
    tin01_parseid pid)
{
    ROUTINE_DBG_MSP00 ("i29_initexecute");
    i29_reset (session, true);
    i29_newsegment (session, sp1m_execute);
    i29_newpart (session, sp1pk_parsid);
    memcpy (session->part->sp1p_buf ().asCharp () + session->part->sp1p_buf_len (),
        pid, sizeof (tin01_parseid));
    session->part->sp1p_buf_len () += sizeof (tin01_parseid);
    /* i29_newpart (session, sp1pk_data); */
}

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

static void
i29_initspecial (
    tin01_sql_session * session,
    tsp1_cmd_mess_type_Param messType)
{
    ROUTINE_DBG_MSP00 ("i29_initspecial");
    i29_reset (session, true);
    i29_newsegment (session, messType);
    i29_newpart (session, sp1pk_command);
}

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

static void
i29_cleanup_session (
    tin01_sql_session * session)
{
    ROUTINE_DBG_MSP00 ("i29_cleanup_session");
    sqlarelease (session->reference);
    session->is_connected = false;
    i29_clearpacketref (session);
}

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

static void
i29_setlasterr_rte (
    tin01_sql_session * session,
    tsp00_ErrText     errtext,
    tsp01_CommErr sp_rc)
{
    ROUTINE_DBG_MSP00 ("i29_setlasterr_rte");
    ASSERT_DBG (session != NULL);
    if (!session->lasterr.lasterr_on)
        return;
    session->lasterr.sp_rc = sp_rc;
    if (sp_rc == commErrOk_esp01)
        return;
    MEMCPY_MIN01 (session->lasterr.errtext, errtext);
    memset (session->lasterr.errname, ' ',
            sizeof (session->lasterr.errname));
}

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

static tsp01_CommErr
i29_request (
    tin01_sql_session * session)
{
    ROUTINE_DBG_MSP00 ("i29_request");
    tsp00_ErrText     errtext;
    tsp01_CommErr  sp_rc;

    ASSERT_DBG (session->is_connected);
    sqlarequest (session->reference, session->send_packet,
        s26packet_len (session->send_packet), errtext, &sp_rc);
    if ((sp_rc == commErrTimeout_esp01) || (sp_rc == commErrCrash_esp01)) {
        i29_cleanup_session (session);
        /*
        sqlarelease (session->reference);
        session->is_connected = false;
        */
    }
    if (sp_rc != commErrOk_esp01) {
        TRACEF_MIN01 (5, (SQLTRACE, "Request error: %40.40s\n",
                errtext));
        if (sp_rc == commErrTimeout_esp01)
            i29reconnect (session);
    }
    i29_setlasterr_rte (session, errtext, sp_rc) ;
    return sp_rc;
}

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

static int
i29_sqlrequest (
    tin01_sql_session * session)
{
    ROUTINE_DBG_MSP00 ("i29_sqlrequest");
  tsp00_Int2         result       = cin01_db_ok;

  if (!session->is_connected) {
    TRACE_MIN01 (4, SQLTRACE, "No connection: command skipped");
    result = cin01_db_not_accessible;
    return result;
  } /* end if */

  ASSERT_DBG (session->is_connected);
  session->rec_packet = NULL;
  i29_closesend (session);
  IFTRACE_MIN01 (4, j96dumppacket (session, "REQUEST", SQLTRACE));

  if (i29_request (session) != commErrOk_esp01) {
    result = cin01_db_not_accessible;
  } /* end if */

  return result;
} /* end i29_sqlrequest */

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

static tsp01_CommErr
i29_receive (
    tin01_sql_session * session)
{
    ROUTINE_DBG_MSP00 ("i29_receive");
    tsp00_Int4        length;
    tsp00_ErrText     errtext;
    tsp01_CommErr  sp_rc;

    ASSERT_DBG (session->is_connected);
    sqlareceive (session->reference, (void**)&session->rec_packet,
        &length, errtext, &sp_rc);
    if ((sp_rc == commErrTimeout_esp01) || (sp_rc == commErrCrash_esp01)) {
        sqlarelease (session->reference);
        session->is_connected = false;
    }
    if (sp_rc != commErrOk_esp01) {
        TRACEF_MIN01 (5, (SQLTRACE, "Receive error: %40.40s\n",
                errtext));
        session->rec_packet = NULL;
    }
    i29_setlasterr_rte (session, errtext, sp_rc) ;
    return sp_rc;
}

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

static int
i29_sqlreceive (
    tin01_sql_session * session)
{
    ROUTINE_DBG_MSP00 ("i29_sqlreceive");
  tsp01_CommErr  comm_error;
  tsp00_Int2         result       = cin01_db_ok;

  comm_error = i29_receive (session);
  i29lasterr_on (session);

  if ((int) comm_error != commErrOk_esp01) {
    if ((int) comm_error == commErrShutdown_esp01 ) {
      result = cin01_db_shutdown;
    } else {
      result = cin01_db_not_accessible;
    } // end if
  } else {
    i29_resetpackets (session, false);
    IFTRACE_MIN01 (4, j96dumppacket (session, "RECEIVE", SQLTRACE));
    result = i29_lastsegment (session->rec_packet)->sp1r_returncode ();
  } /* end if */

  return result;

} /* end i29_sqlreceive */

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

static void
i29_callsql (
    tin01_sql_session * session,
    tsp01_CommErr * comm_error)
{
    ROUTINE_DBG_MSP00 ("i29_callsql");
    *comm_error = i29_request (session);
    if (*comm_error == commErrOk_esp01)
        *comm_error = i29_receive (session);
    i29lasterr_on (session);
}

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

static tsp00_Int4
i29_resultcount (
    tin01_sql_session * session)
{
    ROUTINE_DBG_MSP00 ("i29_resultcount");
    tsp00_Int4        result = UNDEF_SP00;
    tin01_byte      *number;
    tsp00_NumError   res;
    tsp1_part      *part_ptr;

    if (i29_findpart (session, sp1pk_resultcount, &part_ptr)) {
        number = part_ptr->sp1p_buf () + 1;
        s40glint ((tsp00_Number*)number, 1,
                (part_ptr->sp1p_buf_len () - 2) * 2, result, res);
    }
    return result;
} /* i29_resultcount */

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

static int
i29_sql (
    tin01_sql_session * session,
    tin01_sqlresult * sqlresult)
{
    ROUTINE_DBG_MSP00 ("i29_sql");
    tsp01_CommErr  comm_error;
    tsp00_Int2        result;
    tsp1_packet    *send_packet = session->send_packet;
    tsp1_segment   *segment;

    if (sqlresult == NULL)
        sqlresult = &(session->lasterr.sqlresult);
    if (!session->is_connected) {
        TRACE_MIN01 (4, SQLTRACE, "No connection: command skipped");
        result = cin01_db_not_accessible;
        if (sqlresult != NULL) {
            sqlresult->returnCode = result;
            M_WARNINGSET (sqlresult->warnings) = EMPTYSET_MIN01;
            sqlresult->errorPos = 0;
            sqlresult->rowCount = 0;
            MEMCPY_MIN01 (sqlresult->sqlstate, "I8888");
            sqlresult->sqlmsg[0] = '\0';
        }
        return result;
    }
    ASSERT_DBG (session->is_connected);
    session->rec_packet = NULL;
    i29_closesend (session);
    IFTRACE_MIN01 (4, j96dumppacket (session, "REQUEST", SQLTRACE));
    i29_callsql (session, &comm_error);
    if ((int) comm_error != commErrOk_esp01) {
        if ((int) comm_error == commErrShutdown_esp01 ) {
          result = cin01_db_shutdown;
        } else {
          result = cin01_db_not_accessible;
        } // end if
        /* session->is_connected = false; lower level routines try reconnect */
        if (sqlresult != NULL) {
            sqlresult->returnCode = result;
            M_WARNINGSET (sqlresult->warnings) = EMPTYSET_MIN01;
            sqlresult->errorPos = 0;
            sqlresult->rowCount = 0;
            MEMCPY_MIN01 (sqlresult->sqlstate, "I8888");
            sqlresult->sqlmsg[0] = '\0';
        }  // end if
    } else {
        i29_resetpackets (session, false);
        IFTRACE_MIN01 (4, j96dumppacket (session, "RECEIVE", SQLTRACE));
        segment = i29_lastsegment (session->rec_packet);
        result = segment->sp1r_returncode ();
        /* to lasterr, only store errors: */
        if ((sqlresult != NULL) &&
            ((result != cin01_db_ok) ||
                (sqlresult != &(session->lasterr.sqlresult)))) {
            sqlresult->returnCode = result;
            M_WARNINGSET(sqlresult->warnings) = M_WARNINGSET
                (segment->sp1r_extern_warning ());
            sqlresult->errorPos = segment->sp1r_errorpos ();
            if (result == cin01_db_row_not_found) {
                sqlresult->rowCount = 0;
            } else {
                sqlresult->rowCount = i29_resultcount (session);
            } // end if
            MEMCPY_MIN01 (sqlresult->sqlstate, segment->sp1r_sqlstate ());
            if (result != cin01_db_ok) {
              if (i29_findpart (session, sp1pk_errortext)) {
                if (IS_UNICODE(session)) {
                  memcpyUCS2ToUTF8  (sqlresult->sqlmsg, session->part->sp1p_buf ().asCharp (), session->part->sp1p_buf_len (), true, cin01_max_error_len);
                } else {
                  memcpyASCIIToASCII(sqlresult->sqlmsg, session->part->sp1p_buf ().asCharp (), session->part->sp1p_buf_len (), true, cin01_max_error_len);
                } // end if
                sqlresult->sqlmsg[s30klen (sqlresult->sqlmsg, ' ', (tsp00_Int4)strlen(sqlresult->sqlmsg))] = '\0';
              } // end if
            }  // end if
        }  // end if
    } // end if
    return result;
}

/*!
  -----------------------------------------------------------------------------
  function:     i29_pcmd
  -----------------------------------------------------------------------------

  description:  prints a command to the current part

  -----------------------------------------------------------------------------
 */
static void i29_pcmd (
    tin01_sql_session * pSession,
    tin01_cstr          szCmd,
    int                 nLen)
{
    ROUTINE_DBG_MSP00 ("i29_pcmd");

    char * pTarget = pSession->part->sp1p_buf () + pSession->part->sp1p_buf_len ();

    nLen = (nLen == UNDEF_SP00) ? (int) strlen (szCmd) : nLen;

    nLen = IS_UNICODE(pSession) ? memcpyUTF8ToUCS2  (pTarget, szCmd, nLen):
                                  memcpyASCIIToASCII(pTarget, szCmd, nLen);

    pSession->part->sp1p_buf_len () += nLen;
} // end i29_pcmd

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

static void
i29_inc_buflen (
    tin01_sql_session * session,
    tsp00_Int4 bufpos,
    int sqllen)
{
    ROUTINE_DBG_MSP00 ("i29_inc_buflen");
    int newlen = bufpos + sqllen;

    /* old: session->part->sp1p_buf_len () += sqllen + 1; */
    if (session->part->sp1p_buf_len () < newlen)
        session->part->sp1p_buf_len () = newlen;
}

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

static void
i29_pnull (
    tin01_sql_session * session,
    int sqllen,
    tsp00_Int4 bufpos)
{
    ROUTINE_DBG_MSP00 ("i29_pnull");
    tin01_byte           *bufaddr;
    tsp1_packet    *send_packet = session->send_packet;

    ASSERT_DBG (send_packet != NULL);
    bufaddr = (tin01_byte *) (session->part->sp1p_buf () + bufpos - 1);
    *bufaddr = (tin01_byte) csp_undef_byte;
#if !defined (FAST)
    memset (bufaddr + 1, '\0', sqllen - 1);
#endif
    i29_inc_buflen (session, bufpos, sqllen);
}

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

static int
i29_parg (
    tin01_sql_session * session,
    const tin01_byte * arg,
    int varlen,  /* in bytes */
    int sqllen,  /* in bytes */
    tsp00_Int4 bufpos,
    char defByte)
{
    ROUTINE_DBG_MSP00 ("i29_parg");
    int             mvlen;
    tin01_byte      *bufaddr;
    int             maxlen;
    tsp1_packet    *send_packet = session->send_packet;

    if (arg == NULL) {
        i29_pnull (session, sqllen, bufpos);
        return cin01_db_ok;
    }
    --sqllen;                   /* because of defined byte */
    ASSERT_DBG (send_packet != NULL);
    /*
     * IFTRACE_MIN01(4, j99tprintf (SQLTRACE, "
     * arg: "PFMT"; varlen: %d; sqllen: %d; bufpos: %ld; %s\n",
     * arg, varlen, sqllen, bufpos, ischar?"is char":"is tin01_byte" ));
     */
    bufaddr = (tin01_byte *) (session->part->sp1p_buf () + bufpos - 1);
    *bufaddr++ = defByte;
    maxlen = sqllen;
    if (varlen < sqllen)
        mvlen = varlen;
    else
        mvlen = sqllen;
    memcpy (bufaddr, arg, mvlen);

    if (maxlen > mvlen) {
        memset (bufaddr + mvlen, defByte, maxlen - mvlen);
    }
    i29_inc_buflen (session, bufpos, sqllen);
    return cin01_db_ok;
}

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

static void
i29_gparseid (
    tin01_sql_session * session,
    tin01_parseid pid)
{
    ROUTINE_DBG_MSP00 ("i29_gparseid");
    tsp1_packet    *rec_packet = session->rec_packet;
    tin01_bool           found;

    ASSERT_DBG (rec_packet != NULL);
    found = i29_findpart (session, sp1pk_parsid);
    if (found) {
        memcpy (pid, session->part->sp1p_buf (), sizeof (tin01_parseid));
    }
    else {
        memset (pid, '\0', sizeof (tin01_parseid));
        pid[mxin1_parseid - 2] = csp1_p_use_adbs;
    }
}

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

static tin01_byte           *
i29_argaddr (
    tin01_sql_session * session,
    tsp00_Int4 bufpos)
{
    ROUTINE_DBG_MSP00 ("i29_argaddr");
    unsigned char  *bufaddr;
    tin01_byte           *byteaddr;
    tin01_byte           *result;
    tsp1_packet    *rec_packet = session->rec_packet;

    ASSERT_DBG (rec_packet != NULL);
    ASSERT_DBG (session->part->sp1p_part_kind () == sp1pk_data);
    byteaddr = session->part->sp1p_buf () + bufpos - 1;
    bufaddr = (unsigned char *) byteaddr;
    if (*bufaddr == (unsigned char) csp_undef_byte)
        result = NULL;
    else
        result = byteaddr + 1;
    return result;
}

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

static void
i29_machinfo (
    tsp00_CodeType *code_type,
    tsp00_SwapKind *swap_kind,
    char          *termid)
{
    ROUTINE_DBG_MSP00 ("i29_machinfo");
    tsp00_Int4        i234;
    char             *c234;
    tsp100_VersionID0 VersionID0;

    *code_type = csp_ascii;
    i234 = 1;
    c234 = (char *) &i234;
    if (c234[3] == 1)
        (*swap_kind).becomes(sw_normal);
    else if (c234[0] == 1)
        (*swap_kind).becomes(sw_full_swapped);
    else
        (*swap_kind).becomes(sw_part_swapped);

    sp100_GetVersionID ( VersionIDType0_esp100, s100buildnumberEx, &VersionID0 );

    sprintf(termid, "%01d%02d%02d",
                    (int) VersionID0.MajorVersion_sp100,
                    (int) VersionID0.MinorVersion_sp100,
                    (int) VersionID0.CorrLevel_sp100);
    memcpy (termid + sizeof (tsp00_C5), csp_comp_db_manager, sizeof (tsp00_C3));
}

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

static int
i29_adbs_noinfo (
    tin01_sql_session * session,
    tin01_cstr cmd)
{
    ROUTINE_DBG_MSP00 ("i29_adbs_noinfo");
    i29_initadbs (session);
    i29_pcmd (session, cmd, UNDEF_SP00);
    return i29_sql (session, NULL);
}

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

static int
i29_parse (
    tin01_sql_session * session,
    tin01_cstr cmd,
    tin01_c_sqlca * sqlca,
    tin01_bool internal)
{
    ROUTINE_DBG_MSP00 ("i29_parse");
    int             rc;
    int             paramCount;

    if (sqlca->inUse)
        return cin01_db_ok;
    i29_initparse (session);
    if (internal)
        session->segment->sp1c_producer ().becomes(sp1pr_internal_cmd);
    i29_pcmd (session, cmd, UNDEF_SP00);
    rc = i29_sql (session, NULL);
    if (rc == cin01_db_ok) {
        i29_gparseid (session, sqlca->pid);
        paramCount = i29paramcount (session);
        if (paramCount > sqlca->varCount)
            paramCount = sqlca->varCount;
/*            rc = -1200; */        /* too few values */
/*        else { */
            sqlca->paramCount = paramCount;
            if (paramCount > 0) {
                tsp1_param_info *pinfo = i29gparaminfo (session, 0);
                int              i;

                for (i = 0; i < paramCount; ++i, ++pinfo) {
                    memcpy (&sqlca->hostVar [i].pinfo, pinfo,
                            sizeof (tsp1_param_info));
                }
            }
            sqlca->inUse = true;
/*        } */
    }
    return rc;
}

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

static int
i29_put_num_string (
    tin01_sql_session * session,
    char *arg,
    tsp1_param_info * paramInfo)
{
    ROUTINE_DBG_MSP00 ("i29_put_num_string");
    tsp00_NumError   res;
    int             frac;

    frac = paramInfo->sp1i_frac;
    switch (paramInfo->sp1i_data_type) {
        case dfloat:
        case dvfloat:
            frac = -1;
            /* fall through */
        case dinteger:
        case dsmallint:
        case dfixed:
            {
                tsp00_Number num;

                s43pstr (&num, 1, paramInfo->sp1i_length, frac,
                    arg, 1, (int)strlen(arg), res);
                if (res != num_ok)
                    return cin01_db_invalid_number;
                return i29_parg (session, num,
                    paramInfo->sp1i_in_out_len,
                    paramInfo->sp1i_in_out_len,
                    paramInfo->sp1i_bufpos, csp_defined_byte);
            }
     default:
            SWITCH_ERROR_DBG_MIN00 ("data type %d not yet implemented",
                paramInfo->sp1i_data_type );
            break;
    }
    return cin01_db_ok;
}

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

static int
i29_put_bool_string (
    tin01_sql_session * session,
    char             * arg,
    int                datalen,
    tsp1_param_info  * paramInfo)
{
    ROUTINE_DBG_MSP00 ("i29_put_bool_string");
   char            BoolVal;
   tsp00_C20         Temp;
   tsp00_Int4        NumVal;
   tsp00_NumError   res;
   int             i;

   if (datalen == UNDEF_SP00)
      datalen = (int)strlen(arg);
   strncpy (Temp, arg, datalen);
   Temp [datalen] = '\0';
   for (i = 0; i < datalen; ++i) {
       Temp [i] = (char) toupper (Temp [i]);
   }

   if (strcmp (Temp, "true") == 0)
      BoolVal = '\1';
   else if (strcmp (Temp, "false") == 0)
      BoolVal = '\0';
   else {
       s45stoi4 (&NumVal, arg, 1, (tsp00_Int4)strlen (arg), res);
       if (res != num_ok)
          return cin01_db_invalid_number;
       if (NumVal == 0)
          BoolVal = '\0';
      else
          BoolVal = '\1';
   }
   return i29_parg (session, &BoolVal, 1, paramInfo->sp1i_in_out_len,
      paramInfo->sp1i_bufpos, csp_defined_byte);
}

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

static int i29_put_ascii_string (
    tin01_sql_session * session,
    tin01_c_hostvar   * hostVar)
{
  ROUTINE_DBG_MSP00 ("i29_put_ascii_string");

  tsp1_param_info *paramInfo = &hostVar->pinfo;

  char * pData;
  int    nLength;
  int    rc;

  if (hostVar->c_type == cin01_c_charpp) {
    pData = *(char **) hostVar->addr;
  } else {
    pData = (char *) hostVar->addr;
  } // end if

  if (hostVar->len >= 0) {
    nLength = (int) hostVar->len;
  } else {
    nLength = (int)strlen ((char*)pData);
  } // end if

  rc = i29_parg (session, pData, nLength, paramInfo->sp1i_in_out_len, paramInfo->sp1i_bufpos, csp_defined_byte);

  return rc;
} // end i29_put_ascii_string

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

static int i29_put_unicode_string (
    tin01_sql_session * session,
    tin01_c_hostvar   * hostVar)
{
  ROUTINE_DBG_MSP00 ("i29_put_unicode_string");

  tsp1_param_info *paramInfo = &hostVar->pinfo;

  char * pData;
  int    nLength;
  int    rc;

  if (hostVar->c_type == cin01_c_charpp) {
    pData = *(char **) hostVar->addr;
  } else {
    pData = (char *) hostVar->addr;
  } // end if

  if (hostVar->len >= 0) {
    nLength = (int) hostVar->len;
  } else {
    nLength = (int)strlen ((char*)pData);
  } // end if

  char * pTemp = new char[paramInfo->sp1i_in_out_len - 1];
  ASSERT_DBG (NOT_NULL_MIN01 (pTemp));

  nLength = memcpyUTF8ToUCS2(pTemp, pData, nLength);

  rc = i29_parg (session, pTemp, nLength, paramInfo->sp1i_in_out_len, paramInfo->sp1i_bufpos, csp_defined_byte);

  delete [] pTemp;

  return rc;
} // end i29_put_unicode_string

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

static int
i29_inarg (
    tin01_sql_session * session,
    tin01_c_hostvar * hostVar)
{
    ROUTINE_DBG_MSP00 ("i29_inarg");
    unsigned char   defByte = csp_undef_byte;
    tsp1_param_info *paramInfo = &hostVar->pinfo;

    if (hostVar->addr == NULL) {
        i29_pnull (session, paramInfo->sp1i_length, paramInfo->sp1i_bufpos);
        return cin01_db_ok;
    }
    switch (paramInfo->sp1i_data_type) {
        case dfixed:
        case dfloat:
        case dvfloat:
        case dsmallint:
        case dinteger:
            if (hostVar->c_type != cin01_c_charp) {
                SWITCH_ERROR_DBG_MIN00 ("Numeric sql type %d not implemented "
                    "for nonstring C type ", paramInfo->sp1i_data_type);
                break;
            }
            return i29_put_num_string (session, (char*)hostVar->addr, paramInfo);
            break;
       case dboolean:
           /* put boolean value */
            if (hostVar->c_type != cin01_c_charp) {
                SWITCH_ERROR_DBG_MIN00 ("%s not implemented "
                    "for nonstring C type ", "boolean");
                break;
           }
           return i29_put_bool_string
                      (session, (char*)hostVar->addr, (int) hostVar->len, paramInfo);
           break;
        case dchb:
        case dvarcharb:
          break;
        case dcha:
        case dche:
        case dvarchara:
        case dvarchare:
        case ddate:
        case dtime:
        case dtimestamp:
          if (IS_UNICODE(session)) {
            return i29_put_unicode_string (session, hostVar);
          } else {
            return i29_put_ascii_string (session, hostVar);
          } // end if
//          break; no break - otherwise compilerwarning "code not reachable"
        case dunicode:
        case dvarcharuni:
          return i29_put_unicode_string (session, hostVar);
          break;
        default:
            SWITCH_ERROR_DBG_MIN00 ("sql type not supported %d",
                (int) paramInfo->sp1i_data_type);
            break;
    }
    return cin01_db_ok;
}

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

static int
i29_inargs (
    tin01_sql_session * session,
    tin01_c_sqlca * sqlca)
{
    ROUTINE_DBG_MSP00 ("i29_inargs");
    int             i;
    tin01_bool           hasDataPart = false;
    int             rc;

    i29_initexecute (session, sqlca->pid);
    for (i = 0; i < sqlca->paramCount; ++i) {
        if (sqlca->hostVar [i].pinfo.sp1i_io_type != sp1io_output) {
            if (!hasDataPart) {
                i29_newpart (session, sp1pk_data);
                hasDataPart = true;
            }
            rc = i29_inarg (session, &sqlca->hostVar[i]);
            if (rc != cin01_db_ok)
                return rc;
        }
    }
    return cin01_db_ok;
}

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

static tsp00_Int4
i29_get_num_param (
    void *addr,
    tsp1_param_info * paramInfo)
{
    ROUTINE_DBG_MSP00 ("i29_get_num_param");
    tsp00_NumError   res;
    tsp00_Int4        resval;

    s40glint ((tsp00_Number*)addr, 1,
        paramInfo->sp1i_in_out_len,
        resval, res);
    return resval;
}

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

static void
i29_num_param_to_string (
    char *DestStr,
    void *addr,
    tsp1_param_info * paramInfo)
{
    ROUTINE_DBG_MSP00 ("i29_num_param_to_string");
    int len;
    tsp00_DecimalPresentation decimal;
    tsp00_NumError res;

    decimal.thousand_token = 'N';
    decimal.zero_point = '.';
    s44egchr (addr, 1,
//        paramInfo->sp1i_in_out_len,
        paramInfo->sp1i_length,
        paramInfo->sp1i_frac, DestStr, 1, len,
        decimal, res);
    DestStr [len] = '\0';
}

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

static tin01_byte           *
i29_longargaddr (
    tin01_sql_session * session,
    tsp1_param_info * paramInfo)
{
    ROUTINE_DBG_MSP00 ("i29_longargaddr");
    unsigned char  *bufaddr;
    tsp00_LongDescriptor  aDescriptor;
    tsp00_LongDescriptor *descriptor;
    tin01_byte           *byteaddr;
    tin01_byte           *result;
    tsp1_packet    *rec_packet = session->rec_packet;

    ASSERT_DBG (rec_packet != NULL);
    ASSERT_DBG (paramInfo->sp1i_length == sizeof (tsp00_LongDescriptor));
    ASSERT_DBG (session->part->sp1p_part_kind () == sp1pk_data);
    byteaddr = session->part->sp1p_buf () + paramInfo->sp1i_bufpos - 1;
    bufaddr = (unsigned char *) byteaddr;
    if (*bufaddr == (unsigned char) csp_undef_byte)
        return NULL;
//    descriptor = (tsp00_LongDescriptor *)(byteaddr + 1);
    descriptor = &aDescriptor;
    memcpy(descriptor, (byteaddr + 1), sizeof(tsp00_LongDescriptor));
    result = session->part->sp1p_buf () + descriptor->ld_valpos () - 1;
    paramInfo->sp1i_length = descriptor->ld_vallen();
    return result;
}

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

static int
i29_get_stringvalue (
    tin01_sql_session    * session,
    tsp1_param_info     * paramInfo,
    tin01_c_hostvar      * hostVar,
    void                * addr)
{
    ROUTINE_DBG_MSP00 ("i29_get_stringvalue");
    int       datalen; /* bytewise */
    char    * hostbuf;

    TRACEF_MIN01 (5, (session->tracer, "i29_get_stringvalue; input value:\n"));
    IFTRACE_MIN01 (5, j99hexbuf (addr, 0,
        paramInfo->sp1i_length * sizeof (tin01_unichar),
        10, session->tracer));
    datalen = s30klen (addr, ' ', paramInfo->sp1i_length);
    if (hostVar->c_type == cin01_c_charpp) {
        hostbuf = (char *) malloc (datalen + 1);
        ASSERT_DBG (NOT_NULL_MIN01 (hostbuf));
        *((void **) hostVar->addr) = hostbuf;
    }
    else
        hostbuf = (char*) hostVar->addr;
    memcpy (hostbuf, addr, datalen);
    hostbuf[datalen] = '\0';
    return cin01_db_ok;
} // i29_get_stringvalue

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

static int i29_get_unicodevalue (
    tin01_sql_session   * session,
    tsp1_param_info     * paramInfo,
    tin01_c_hostvar     * hostVar,
    void                * addr)
{
  ROUTINE_DBG_MSP00 ("i29_get_unicodevalue");
  char    * hostbuf;
  int       nLen;

  TRACEF_MIN01 (5, (session->tracer, "i29_get_unicodevalue; input value:\n"));
  IFTRACE_MIN01 (5, j99hexbuf (addr, 0, paramInfo->sp1i_length * sizeof (tin01_unichar), 10, session->tracer));

  if (hostVar->c_type == cin01_c_charpp) {
    hostbuf = (char *) malloc (paramInfo->sp1i_length + 1);
    ASSERT_DBG (NOT_NULL_MIN01 (hostbuf));
    *((void **) hostVar->addr) = hostbuf;
  } else {
    hostbuf = (char*) hostVar->addr;
  } // end if

  nLen = memcpyUCS2ToUTF8(hostbuf, (const char *) addr, paramInfo->sp1i_length * 2, true);

  hostbuf[s30klen (hostbuf, ' ', nLen)] = '\0';

  return cin01_db_ok;
} // end i29_get_unicodevalue

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

static int
i29_outarg (
    tin01_sql_session * session,
    tin01_c_hostvar * hostVar)
{
    ROUTINE_DBG_MSP00 ("i29_outarg");
    void           *addr;
    char           *hostbuf;
    tsp1_param_info * paramInfo = &hostVar->pinfo;
    int             rc = cin01_db_ok;

    switch (paramInfo->sp1i_data_type) {
        case dstra:
        case dstre:
        case dstrb:
        case dstrdb:
            addr = i29_longargaddr (session, paramInfo);
            break;
        default:
            addr = i29_argaddr (session, paramInfo->sp1i_bufpos);
            break;
    }
    if (addr == NULL) {
        hostVar->is_null = true;
        return rc;
    }
    else
        hostVar->is_null = false;
    switch (paramInfo->sp1i_data_type) {
        case dfixed:
        case dfloat:
        case dvfloat:
        case dsmallint:
        case dinteger:
            switch (hostVar->c_type) {
                case cin01_c_short:
                    *((short *) hostVar->addr) =
                        (short) i29_get_num_param (addr, paramInfo);
                    break;
                case cin01_c_ushort:
                    *((unsigned short *) hostVar->addr) =
                        (unsigned short) i29_get_num_param (addr, paramInfo);
                    break;
                case cin01_c_int:
                    *((int *) hostVar->addr) =
                        (int) i29_get_num_param (addr, paramInfo);
                    break;
                case cin01_c_uint:
                    *((unsigned int *) hostVar->addr) =
                        (unsigned int) i29_get_num_param (addr, paramInfo);
                    break;
                case cin01_c_long:
                    *((long *) hostVar->addr) =
                        i29_get_num_param (addr, paramInfo);
                    break;
                case cin01_c_ulong:
                    *((unsigned long *) hostVar->addr) =
                        (unsigned long) i29_get_num_param (addr, paramInfo);
                    break;
                case cin01_c_charp:
                    i29_num_param_to_string ((char*) hostVar->addr, addr, paramInfo);
                    break;
                default:
                    SWITCH_ERROR_DBG_MIN00 ("FIXED to hostvar type %d not supported",
                        (int) hostVar->c_type);
                    break;
            }
            break;
        case dcha:
        case dche:
        case dchb:
        case dvarchara:
        case dvarchare:
        case dvarcharb:
        case ddate:
        case dtime:
        case dtimestamp:
        case dstra:
        case dstre:
        case dstrb:
        case dstrdb:
            if (IS_UNICODE(session)) {
              rc = i29_get_unicodevalue (session, paramInfo, hostVar, addr);
            } else {
              rc = i29_get_stringvalue (session, paramInfo, hostVar, addr);
            } // end if
            break;
        case dvarcharuni:
        case dunicode:
            rc = i29_get_unicodevalue (session, paramInfo, hostVar, addr);
            break;
        case dboolean:
           {
               const char *result;
               hostbuf = (char*) hostVar->addr;
               if (hostVar->c_type == cin01_c_charp) {
                   if (*((char *)addr))
                       result = "true";
                   else
                       result = "false";

                   strcpy (hostbuf, result);
               }
               else {
                   SWITCH_ERROR_DBG_MIN00 ("boolean not supported for C type %d",
                       (int) hostVar->c_type);
               }
               break;
           }
        default:
            SWITCH_ERROR_DBG_MIN00 ("sql type not supported %d",
                (int) paramInfo->sp1i_data_type);
            break;
    }
    return rc;
}

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

static int
i29_outargs (
    tin01_sql_session * session,
    tin01_c_sqlca * sqlca)
{
    ROUTINE_DBG_MSP00 ("i29_outargs");
    int             i;
    int             rc = cin01_db_ok;

    i29_findpart (session, sp1pk_data);
    for (i = 0; i < sqlca->paramCount; ++i) {
        if ((int) sqlca->hostVar [i].pinfo.sp1i_io_type != sp1io_input) {
            rc = i29_outarg (session, &sqlca->hostVar[i]);
            if (rc != cin01_db_ok)
                return rc;
        }
    }
    return rc;
}

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

static tin01_bool
i29_try_again (
    int rc)
{
    ROUTINE_DBG_MSP00 ("i29_try_again");
    tin01_bool           result;

    switch (rc) {
        case -8:               /* parse again */
        case 500:              /* wait for lock release */
        case 700:              /* timeout */
            result = true;
            break;
        default:
            result = false;
            break;
    }
    return result;
}

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

/* checks if a data type of the db is a string type
   (for seting of string delimiter sin the result) */
static tin01_bool
i29_isstring (tsp00_DataType aDataType)
{
    ROUTINE_DBG_MSP00 ("i29_isstring");

  tin01_bool bRc = false;

  switch(aDataType) {
    /* Had I hit all data types??? */
    case dcha:
    case dche:
    case dchb:
    case dunicode:
    case dvarchara:
    case dvarchare:
    case dvarcharb:
    case ddate:
    case dtime:
    case dtimestamp:
    case dstra:
    case dstre:
    case dstrb:
    case dstrdb:
      bRc = true;
  } /* end switch */

  return bRc;

} /* end i29_isstring */

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

/* calculates a approximate length of one result record */
static int
i29_rowlen (
    tin01_sql_session  * session)
{
    ROUTINE_DBG_MSP00 ("i29_rowlen");

    int               nParamCount = 0,
                      i           = 0,
                      nRowLen     = 0;
    tsp1_param_info * pParamInfo  = NULL;

    /**/

    /* get some infos */
    pParamInfo = i29gparaminfo(session, 0);
    nParamCount = i29paramcount(session);

    /* calculate approximate rowlen */
    for (i = 0; i < nParamCount; i++) {
      nRowLen = nRowLen + ((pParamInfo[i].sp1i_length < cin29_min_len) ? pParamInfo[i].sp1i_length : cin29_min_len);
    } /* end for */

    /**/

    return nRowLen;

} /* end i29_rowlen */

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

static void i29_connectcommand (
    tin01_sql_session *   session,
    tsp00_TermId          termid)
{
  ROUTINE_DBG_MSP00 ("i29_connectcommand");

  char          szConnCmd[c_connect_len + 1] = "";
  tin01_byte  * pData                        = NULL;
  tsp00_Name    strPwdP;
  tsp00_Name    strPwdU;
  tsp00_CryptPw cryptPwd;

  session->buildingCommand = false;

  // make connect command
  i29_initadbs (session);
  session->segment->sp1c_producer ().becomes(sp1pr_internal_cmd);

  sp77sprintf (szConnCmd, 
               c_connect_len, 
               "CONNECT \"%s\" IDENTIFIED by :PW",
               session->szUser.asCharp());

  i29_pcmd(session, szConnCmd, UNDEF_SP00);

  // create data part for pwd and termid
  i29_newpart (session, sp1pk_data);

  pData = session->part->sp1p_buf () + session->part->sp1p_buf_len ();
  *pData = csp_defined_byte;

  // password
  strPwdP.c2p(session->szPwd);
  if (IS_UNICODE(session)) {
    memcpyUTF8ToUCS2  (strPwdU, strPwdP, sizeof(strPwdP), false, sizeof(strPwdU));
  } else {
    memcpyASCIIToASCII(strPwdU, strPwdP, sizeof(strPwdP), false, sizeof(strPwdU));
  } // end if
  s02applencrypt (strPwdU, cryptPwd);
  memcpy (pData + 1, cryptPwd, sizeof(cryptPwd));
  session->part->sp1p_buf_len () +=  1 + sizeof(cryptPwd);

  // termid
  pData = session->part->sp1p_buf () + session->part->sp1p_buf_len ();
  *pData = csp_defined_byte;
  memcpy (pData + 1, termid, sizeof(termid));
  session->part->sp1p_buf_len () += 1 + sizeof(termid);

} // end i29_connectcommand

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

static void
i29_fetchcmd (
    tin01_sql_session * session,
    tin01_cstr fetchCmd,
    int fetchVars)
{
    char           * szBuffer = new char[strlen(fetchCmd) + c_intolen + (c_varlen * (fetchVars)) + 1];
    ASSERT_DBG (NOT_NULL_MIN01 (szBuffer));

    i29_initadbs (session);

    if (szBuffer != NULL) {
      strcpy(szBuffer, fetchCmd);
      strcat(szBuffer, c_intostr);
      --fetchVars;
      while (fetchVars > 0) {
        strcat(szBuffer, c_varstr);
        --fetchVars;
      } // end while

      i29_pcmd(session, szBuffer, UNDEF_SP00);
    } // end if

    delete [] szBuffer;

}

/*----------------------------------------*/
static void
i29_initutility (
    tin01_sql_session * session)
{
    ROUTINE_DBG_MSP00 ("i29_initutility");
    i29_reset (session, true);
    i29_newsegment (session, sp1m_utility);
    i29_newpart (session, sp1pk_command);
}

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

/* gets the selected records in the result buffer until
   nResultLen is reached
   (at first in the result buffer a keyword (END or CONTINUE)
   will indicate whether the end of result is reached or not) */
static int
i29_fetchnext (
    tin01_sql_session * session,
    char              * pResult,
    long                nResultLen,
    char                cFieldSep,
    char                cStringDel,
    char                cRecSep,
    bool              & bContinue)
{
    ROUTINE_DBG_MSP00 ("i29_fetchnext");

    int               rc          = cin01_db_ok,
                      i           = 0,
                      nParamCount = 0,
                      nRowLen     = i29_rowlen(session);
    tsp1_param_info * pParamInfo  = NULL;
    char            * pCurrent    = pResult;
    char            * pContinue   = NULL;
    tin01_c_hostvar    aHostVar;

    /**/

    *pResult = 0;
    bContinue = false;

    /* place for end/continue mark */
    pContinue = pCurrent;
    pCurrent  = pCurrent + cin29_cont_len;

    while ((rc == cin01_db_ok) && (pCurrent - pResult + nRowLen < nResultLen) ) {

      /* get some infos */
      pParamInfo = i29gparaminfo(session, 0);
      nParamCount = i29paramcount(session);

      i29_findpart (session, sp1pk_data);
      for (i = 0; i < nParamCount; i++) {

        /* set string delimiter */
        if (i29_isstring(pParamInfo[i].sp1i_data_type) && cStringDel != 0) {
          *pCurrent++ = cStringDel;
        } /* end if */

        /* fill hostvar struct */
        memset(&aHostVar, 0, sizeof(aHostVar));
        aHostVar.len = -1;
        aHostVar.c_type.becomes(cin01_c_charp);
        memcpy(&(aHostVar.pinfo), &pParamInfo[i], sizeof(tsp1_param_info));
        aHostVar.addr = pCurrent;
        *((char *) (aHostVar.addr)) = 0;

        /* read value */
        rc = i29_outarg (session, &aHostVar);

        /* check for <NULL> */
        if (aHostVar.is_null) {
          /* skip string delimiter */
          if (i29_isstring(pParamInfo[i].sp1i_data_type) && cStringDel != 0) {
            pCurrent--;
          } /* end if */
          strcpy(pCurrent, cin29_nulltext);
        } /* end if */

        pCurrent = pCurrent + strlen(pCurrent);

        /* set string delimiter */
        if (i29_isstring(pParamInfo[i].sp1i_data_type) && !aHostVar.is_null  && cStringDel != 0) {
          *pCurrent++ = cStringDel;
        } /* end if */

        if (cFieldSep != 0) {
          *pCurrent++ = cFieldSep;
        } /*end if */
      } /* end for */

      /* skip last field separator */
      if (cFieldSep != 0) {
        pCurrent--;
      } /*end if */
      if (cRecSep != 0) {
        *pCurrent++ = cRecSep;
      } /*end if */

      /* next row */
      i29_fetchcmd (session, "FETCH NEXT", nParamCount);
      session->segment->sp1c_with_info () = true;
      rc =  i29_sql (session, NULL);
    } /* end while */

    /* handle end/continue mark */
    if (rc == cin01_db_ok) {
      strncpy(pContinue, cin29_cont_cont, cin29_cont_len);
      bContinue = true;
    } else if (rc == cin01_db_row_not_found) {
      strncpy(pContinue, cin29_cont_end, cin29_cont_len);
      rc = cin01_db_ok;
    } /* end if */

    /* skip last record separator */
    if (cRecSep != 0) {
      pCurrent--;
    } /* end if */

    *pCurrent = 0;

    return rc;

} /* end i29_fetchnext */

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

static int i29_fetchnice (
    tin01_sql_session * session,
    char              * pResult,
    char              * pCurrent,
    char              * pContinue,
    long                nResultLen,
    bool                bOneRowResult,
    long                nMaxNameLen,
    int                 nRowLen,
    bool                bDataOnly,
    bool              & bContinue)
{
    ROUTINE_DBG_MSP00 ("i29_fetchnice");

    int               rc          = cin01_db_ok;
    int               i           = 0;
    int               nParamCount = 0;
    tsp1_param_info * pParamInfo  = NULL;
    tin01_c_hostvar   aHostVar;
    int               nLen        = 0;
    int               nOutLen     = 0;
    int               nMaxLen     = 0;

    /**/

    bContinue = false;

    while ((rc == cin01_db_ok) &&
           (pCurrent - pResult + nRowLen < nResultLen)) {

      /* get some infos */
      tin01_cstr pNames = i29colnames(session);

      pParamInfo  = i29gparaminfo(session, 0);
      nParamCount = i29paramcount(session);

      i29_findpart (session, sp1pk_data);
      for (i = 0; i < nParamCount; i++) {

        nLen = *pNames++;

        if (bOneRowResult) {

          nOutLen = IS_UNICODE(session) ? memcpyUCS2ToUTF8  (pCurrent, pNames, nLen):
                                          memcpyASCIIToASCII(pCurrent, pNames, nLen);
          pCurrent += nOutLen;
          memset(pCurrent, 32, nMaxNameLen - nOutLen);
          pCurrent += (nMaxNameLen - nOutLen);
          strcpy(pCurrent, " = ");
          pCurrent = pCurrent + strlen(pCurrent);
        } // end inf

        pNames += nLen;

        nMaxLen = IS_UNICODE(session) ? (nLen / 2) : nLen;
        nMaxLen = (pParamInfo[i].sp1i_length > nMaxLen) ? pParamInfo[i].sp1i_length : nMaxLen;

        /* fill hostvar struct */
        memset(&aHostVar, 0, sizeof(aHostVar));
        aHostVar.len = -1;
        aHostVar.c_type.becomes(cin01_c_charp);
        memcpy(&(aHostVar.pinfo), &pParamInfo[i], sizeof(tsp1_param_info));
        aHostVar.addr = pCurrent;
        *((char *) (aHostVar.addr)) = 0;

        /* read value */
        rc = i29_outarg (session, &aHostVar);

        /* check for <NULL> */
        if (aHostVar.is_null) {
          strcpy(pCurrent, " "); /* cin29_nulltext */
        }

        nLen = (int)strlen(pCurrent);

        pCurrent = pCurrent + nLen;

        memset(pCurrent, 32, nMaxLen - nLen);
        pCurrent += (nMaxLen - nLen);

        if (bOneRowResult) {
          *pCurrent++ = '\n';
        } else {
          if (i < (nParamCount -1 )) {
            *pCurrent++ = ' ';
            *pCurrent++ = '|';
            *pCurrent++ = ' ';
          }
        }
      }

      if (!bOneRowResult) {
        *pCurrent++ = '\n';
      }

      /* next row */
      i29_fetchcmd (session, "FETCH NEXT", nParamCount);
      session->segment->sp1c_with_info () = true;
      rc =  i29_sql (session, NULL);

    } /* end while */

    /* handle end/continue mark */
  if (!bDataOnly) {
      if (rc == cin01_db_ok) {
        strncpy(pContinue, cin29_cont_cont, cin29_cont_len);
        bContinue = true;
    } else if (rc == cin01_db_row_not_found) {
        strncpy(pContinue, cin29_cont_end, cin29_cont_len);
        rc = cin01_db_ok;
    } /* end if */
  }

    *pCurrent = 0;

    return rc;
} /* end i29_fetchnice */

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

static int
i29_connect (
    tin01_sql_session * session,
    tsp01_Service       connectKind)
{
    ROUTINE_DBG_MSP00 ("i29_connect");

    tsp00_TaskId        aid;
    tsp00_ErrText       errtext;
    tsp01_CommErr       sp_rc;
    tsp00_Int4          packetSize;
    void              * packetList [1];
    tsp00_DbName        strDbP;
    tsp00_NodeId        strNodeP;

    sqluid (&aid);

    strDbP.c2p(session->szDB);
    strNodeP.c2p(session->szNode);

    sqlaconnect (aid, strNodeP, strDbP,
        connectKind, 1, &session->reference, &packetSize,
        packetList, errtext, &sp_rc);

    if (sp_rc != commErrOk_esp01) {

      TRACEF_MIN01 (5, (SQLTRACE, "Connect error: %40.40s\n", errtext));
      i29_setlasterr_rte (session, errtext, sp_rc) ;

    } else {

      ASSERT_DBG (!session->is_connected);
      session->send_packet = (tsp1_packet_ptr ) packetList [0];
      session->send_packet->sp1_header.sp1h_varpart_size = packetSize - sizeof (tsp1_packet_header);
      session->is_connected = true;

    }
    return sp_rc;
} /* end i29_connect */

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

static tin01_sql_session *
i29_lasterr_off (
    tin01_sql_session * session)
{
    ROUTINE_DBG_MSP00 ("i29_lasterr_off");
    session->lasterr.lasterr_on = false;
    return session;
} /* i29_lasterr_off */

/*
  -----------------------------------------------------------------------------
  implementation public functions
  -----------------------------------------------------------------------------
*/

int i29selectnice (
    tin01_sql_session  * session,
    tin01_cstr           cmd,
    char               * pResult,
    long                 nResultLen,
    bool                 bOneRowResult,
    bool                 bDesc,
    bool                 bDataOnly,
    bool              & bContinue)
{
    ROUTINE_DBG_MSP00 ("i29selectnice");

    int               rc           = cin01_db_ok;
    int               i            = 0;
    int               j            = 0;
    int               nParamCount  = 0;
    tin01_cstr        pNames       = NULL;
    char            * pCurrent     = pResult;
    char            * pContinue    = NULL;
    char            * pHeader      = NULL;
    int               nLen         = 0;
    int               nOutLen      = 0;
    int               nMaxNameLen  = 0;
    int               nMaxParamLen = 0;
    tsp1_param_info * pParamInfo   = NULL;
    int               nMaxLen      = 0;
    int               nRowLen      = 0;

    char              szDesc[255];

    /**/

    *pResult = 0;

    pContinue = pCurrent;
    if (!bDataOnly) {
      pCurrent  = pCurrent + cin29_cont_len;
    }
    pHeader   = pCurrent;

    /* prepare statement execution */
    i29_initadbs (session);
    session->segment->sp1c_with_info () = true;
    i29_pcmd (session, cmd, UNDEF_SP00);

    /* execute statement */
    rc = i29_sql (session, NULL);

    if (rc == cin01_db_ok) {

      pParamInfo  = i29gparaminfo(session, 0);
      nParamCount = i29paramcount(session);
      pNames      = i29colnames(session);

      // make datatype description
      if (bDesc) {

        szDesc[0] = '\0';

        if (bOneRowResult) {
          strcat(szDesc, "SS");
        } // end if

        for (i = 0; i < nParamCount; i++) {
          switch (pParamInfo[i].sp1i_data_type) {
            case dfixed:    case dfloat:    case dvfloat:
            case dsmallint: case dinteger:
              strcat(szDesc, "N");
              break;
            case dcha:      case dche:      case dchb:
            case dunicode:  case dvarchara: case dvarchare:
            case dvarcharb: case dstra:     case dstre:
            case dstrb:     case dstrdb:
              strcat(szDesc, "S");
              break;
            case ddate:     case dtime:     case dtimestamp:
              strcat(szDesc, "D");
              break;
          case dboolean:
              strcat(szDesc, "B");
              break;
          default:
              strcat(szDesc, "-");
              break;
          } // end switch 
        } // end for
        strcat(szDesc, "\n");
        strcpy(pCurrent, szDesc);
        pCurrent += strlen(pCurrent);
      } // end if

      // handling columns
      for (i = 0; i < nParamCount; i++) {

        nLen = *pNames++;

        // compute max. length of data
        if (pParamInfo[i].sp1i_length > nMaxParamLen) {
          nMaxParamLen = pParamInfo[i].sp1i_length;
        } // end if

        if (bOneRowResult) {

          // compute max. length of column names
          if (IS_UNICODE(session)) {
            nMaxNameLen = ((nLen/2) > nMaxNameLen) ? (nLen/2) : nMaxNameLen;
          } else {
            nMaxNameLen = (nLen > nMaxNameLen) ? nLen : nMaxNameLen;
          } // end if
          pNames += nLen;

        } else {

          nMaxLen = IS_UNICODE(session) ? (nLen / 2) : nLen;
          nMaxLen = (pParamInfo[i].sp1i_length > nMaxLen) ? pParamInfo[i].sp1i_length : nMaxLen;

          nOutLen = IS_UNICODE(session) ? memcpyUCS2ToUTF8  (pCurrent, pNames, nLen):
                                          memcpyASCIIToASCII(pCurrent, pNames, nLen);

          pCurrent += nOutLen;
          memset(pCurrent, 32, nMaxLen - nOutLen);
          pCurrent += (nMaxLen - nOutLen);
          if (i < (nParamCount - 1)) {
            strcpy(pCurrent, " | ");
          } else {
            strcpy(pCurrent, "\n\n");
          }
          pCurrent += strlen(pCurrent);
          pNames += nLen;

        } // end if
      } // end for

      if (bOneRowResult) {
        strcpy(pCurrent, "Name");
        pCurrent += strlen(pCurrent);
        memset(pCurrent, 32, nMaxNameLen - 4);
        pCurrent += (nMaxNameLen - 4);
        strcpy(pCurrent, " | Value");
        pCurrent += strlen(pCurrent);
        memset(pCurrent, 32, nMaxParamLen - 5);
        pCurrent += (nMaxParamLen - 5);
        strcpy(pCurrent, "\n\n");
        pCurrent += strlen(pCurrent);
      }

      if (!bOneRowResult) {
        nRowLen = (int)strlen(pHeader) - 1;
      } else {
        nRowLen = (nMaxNameLen + nMaxParamLen + 4) * nParamCount;
      } // end if

    if (bDataOnly) {
        pCurrent = pHeader;
    }

    }

    /* get first row */
    if (rc == cin01_db_ok) {
      i29_fetchcmd (session, "FETCH FIRST", nParamCount);
      session->segment->sp1c_with_info () = true;
      rc =  i29_sql (session, NULL);
    }

    /* analyze rows */
    if (rc == cin01_db_ok) {
      rc = i29_fetchnice(session, pResult, pCurrent, pContinue, nResultLen, bOneRowResult, nMaxNameLen, nRowLen, bDataOnly, bContinue);
    }

    if (rc == cin01_db_row_not_found) {
      rc = cin01_db_ok;
    }

    return rc;
} /* end i29selectnice */

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

int i29fetchnice (
    tin01_sql_session  * session,
    char               * pResult,
    long                 nResultLen,
    bool               & bContinue)
{
    ROUTINE_DBG_MSP00 ("i29fetchnice");

    int               rc          = cin01_db_ok;
    int               i           = 0;
    int               j           = 0;
    int               nParamCount = 0;
    tin01_cstr        pNames      = NULL;
    char            * pCurrent    = pResult;
    char            * pContinue   = NULL;
    char            * pHeader     = NULL;
    char              nLen        = 0;
    char              nMaxNameLen = 0;
    tsp1_param_info * pParamInfo  = NULL;
//  char              nMaxLen     = 0;
    short             nMaxLen     = 0;
    int               nRowLen     = 0;

    /**/

    *pResult = 0;

    pContinue = pCurrent;
    pCurrent  = pCurrent + cin29_cont_len;
    pHeader   = pCurrent;

    pParamInfo  = i29gparaminfo(session, 0);
    nParamCount = i29paramcount(session);
    pNames      = i29colnames(session);

    for (i = 0; i < nParamCount; i++) {
      nLen = *pNames;

      nMaxLen = nLen;
      if (pParamInfo[i].sp1i_length > nLen) {
        nMaxLen = pParamInfo[i].sp1i_length;
      }
      pNames++;
      memcpy(pCurrent, pNames, nLen);
      pCurrent += nLen;
      memset(pCurrent, 32, nMaxLen - nLen);
      pCurrent += (nMaxLen - nLen);
      if (i < (nParamCount - 1)) {
        strcpy(pCurrent, " | ");
      } else {
        strcpy(pCurrent, "\n\n");
      }
      pCurrent += strlen(pCurrent);
      pNames += nLen;
    }

    nRowLen = (int)strlen(pHeader) - 1;

    /* get next row */
//    i29_fetchcmd (session, "FETCH NEXT", nParamCount);
//    session->segment->sp1c_with_info () = true;
//    rc = i29_sql (session, NULL);

    /* analyze rows */
    if (rc == cin01_db_ok) {
      rc = i29_fetchnice(session, pResult, pCurrent, pContinue, nResultLen, false, nMaxNameLen, nRowLen, false, bContinue);
    }

    /**/

    return rc;
} /* end i29fetchnice */

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

/* puts infos about the result of the select statement
   into the result buffer
   at the moment (1998-04-20 - BV)  only the field names */
int i29selectinfo (
    tin01_sql_session  * session,
    tin01_cstr           cmd,
    char              * pResult,
    char                cFieldSep)
{
    ROUTINE_DBG_MSP00 ("i29selectinfo");

    int               rc          = cin01_db_ok,
                      i           = 0,
                      j           = 0,
                      nParamCount = 0;
    tin01_cstr        pNames      = NULL;
    char            * pCurrent    = pResult;
    int               nLen        = 0;
    int               nOutLen     = 0;

    /**/

    *pResult = 0;

    /* prepare statement execution */
    i29_initadbs (session);
    session->segment->sp1c_with_info () = true;
    session->segment->sp1c_producer ().becomes(sp1pr_internal_cmd);
    i29_pcmd (session, cmd, UNDEF_SP00);

    /* execute statement */
    rc = i29_sql (session, NULL);

    /* analyze result */
    if (rc == cin01_db_ok) {

      /* get some infos */
      nParamCount = i29paramcount(session);
      pNames      = i29colnames(session);

      /* get columns */
      for (i = 0; i < nParamCount; i++) {
        nLen = *pNames++;

        nOutLen = IS_UNICODE(session) ? memcpyUCS2ToUTF8  (pCurrent, pNames, nLen):
                                        memcpyASCIIToASCII(pCurrent, pNames, nLen);

        pCurrent += nOutLen;
        pNames   += nLen;
        if (cFieldSep != 0) {
          *pCurrent++ = cFieldSep;
        } /* end if */
      } /* end for */
      /* skip last field separator */
      if (cFieldSep != 0) {
        pCurrent--;
      } /* end if */
    } /* end if */

    *pCurrent = 0;

    return rc;
} /* end i29selectinfo */

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

/* execute a select statement and call i29_fetchnext
   for retrieving (the first part) of the result
   (try to execute a non select statement will produce an error
   in the kernel) */
int i29select (
    tin01_sql_session  * session,
    tin01_cstr           cmd,
    char              * pResult,
    long                nResultLen,
    char                cFieldSep,
    char                cStringDel,
    char                cRecSep,
    bool              & bContinue)
{
    ROUTINE_DBG_MSP00 ("i29select");

    int rc = cin01_db_ok;

    /**/

    *pResult = 0;

    /* prepare statement execution */
    i29_initadbs (session);
    session->segment->sp1c_with_info () = true;
    session->segment->sp1c_producer ().becomes(sp1pr_internal_cmd);
    i29_pcmd (session, cmd, UNDEF_SP00);

    /* execute statement */
    rc = i29_sql (session, NULL);

    /* get first row */
    if (rc == cin01_db_ok) {
      i29_fetchcmd (session, "FETCH FIRST", i29paramcount(session));
      session->segment->sp1c_with_info () = true;
      rc =  i29_sql (session, NULL);
    } /* end if */

    /* analyze rows */
    if (rc == cin01_db_ok) {
      rc = i29_fetchnext(session, pResult, nResultLen, cFieldSep, cStringDel, cRecSep, bContinue);
    } /* end if */

   return rc;
} /* end i29select */

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

/* retrieve the next part of a result. no open select
   in the session will produce an error */
int i29fetch (
    tin01_sql_session  * session,
    char              * pResult,
    long                nResultLen,
    char                cFieldSep,
    char                cStringDel,
    char                cRecSep,
    bool              & bContinue)
{
    ROUTINE_DBG_MSP00 ("i29fetch");

    int rc = cin01_db_ok;

    /**/

    *pResult = 0;

    /* get next row */
//    i29_fetchcmd (session, "FETCH NEXT", i29paramcount(session));
//    session->segment->sp1c_with_info () = true;
//    rc =  i29_sql (session, NULL);

    /* analyze rows */
    if (rc == cin01_db_ok) {
      rc = i29_fetchnext(session, pResult, nResultLen, cFieldSep, cStringDel, cRecSep, bContinue);
    } /* end if */

    /**/

    return rc;
} /* end i29fetch */

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

int i29record (
    tin01_sql_session  * session,
    tin01_cstr           cmd)
{
  ROUTINE_DBG_MSP00 ("i29record");

  int rc = cin01_db_ok;

  /**/

  /* prepare statement execution */
  i29_initadbs (session);
  session->segment->sp1c_with_info () = true;
  session->segment->sp1c_producer ().becomes(sp1pr_internal_cmd);
  i29_pcmd (session, cmd, UNDEF_SP00);

  /* execute statement */
  rc = i29_sql (session, NULL);

  /* get first row */
  if (rc == cin01_db_ok) {
    i29_fetchcmd (session, "FETCH FIRST", i29paramcount(session));
    session->segment->sp1c_with_info () = true;
    rc =  i29_sql (session, NULL);
  } /* end if */

  /**/

  return rc;
} /* end i29record */

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

int i29nextrecord (
    tin01_sql_session  * session)
{
  ROUTINE_DBG_MSP00 ("i29nextrecord");

  int rc = cin01_db_ok;

  /**/

  /* get next row */
  i29_fetchcmd (session, "FETCH NEXT", i29paramcount(session));
  session->segment->sp1c_with_info () = true;
  rc =  i29_sql (session, NULL);

  /**/

  return rc;
} /* end i29nextrecord */

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

int i29fieldvalue (
    tin01_sql_session  * session,
    const tsp00_Int4     nField,
    tin01_c_hostvar    * pHostvar,
    const char           cStringQuote)

{
  ROUTINE_DBG_MSP00 ("i29fieldvalue");

  int               rc          = cin01_db_ok;
  tsp1_param_info * pParamInfo  = NULL;
  int               nParamCount = 0;
  char            * pChar       = (char *) pHostvar->addr;
  /**/

  pParamInfo  = i29gparaminfo(session, 0);
  nParamCount = i29paramcount(session);

  if (nParamCount >= nField) {
    memcpy(&(pHostvar->pinfo), &pParamInfo[nField - 1], sizeof(tsp1_param_info));
    i29_findpart (session, sp1pk_data);

    // handle strings
    if (i29_isstring(pHostvar->pinfo.sp1i_data_type) && cStringQuote != 0) {
      *pChar = cStringQuote;
      ++pChar;
      pHostvar->addr = pChar;
    } // end if

    /* read value */
    rc = i29_outarg (session, pHostvar);

    // handle strings
    if (i29_isstring(pHostvar->pinfo.sp1i_data_type) && cStringQuote != 0) {
      if (rc == cin01_db_ok) {
        pChar[strlen(pChar)    ] = cStringQuote;
        pChar[strlen(pChar) + 1] = 0;
      } // end if

      --pChar;
      pHostvar->addr = pChar;
    } // end if
  } else {
    rc = cin01_db_invalid_number;
  } // end if

  /**/

  return rc;
} /* end i29fieldvalue */

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

char * i29fieldname (
    tin01_sql_session  * session,
    const tsp00_Int4     nField,
    char               * pResult)

{
  ROUTINE_DBG_MSP00 ("i29fieldname");

  int               i           = 0;
  int               nParamCount = 0;
  tin01_cstr        pNames      = NULL;
  int               nLen        = 0;
  int               nOutLen     = 0;

  /**/

  *pResult = 0;

  /* get some infos */
  nParamCount = i29paramcount(session);
  pNames      = i29colnames(session);

  /* get columns */
  for (i = 1; i <= nParamCount; i++) {
    nLen = *pNames++;
    if (i == nField) {
        nOutLen = IS_UNICODE(session) ? memcpyUCS2ToUTF8  (pResult, pNames, nLen):
                                        memcpyASCIIToASCII(pResult, pNames, nLen);
        pResult[nOutLen] = 0;
        break;
    } // end if

    pNames += nLen;
  } /* end fot */

  /**/

  return pResult;
} /* end i29fieldname */

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

int i29utility (
    tin01_sql_session * session,
    tin01_cstr cmd)
{
    ROUTINE_DBG_MSP00 ("i29utility");
    i29_initutility (session);
    i29_pcmd (session, cmd, UNDEF_SP00);
    return i29_sql (session, NULL);
}

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

int i29utilitynice (
    tin01_sql_session   * session,
    tin01_cstr            cmd,
    char                * pResult,
    bool                  bSessionless)
{
  ROUTINE_DBG_MSP00 ("i29utilitynice");

  int               rc          = 0;
  int               i           = 0;
  int               nParamCount = 0;
  size_t            nLen        = 0;
  size_t            nOutLen     = 0;
  tsp1_param_info * pParamInfo  = NULL;
  char            * pCurrent    = pResult;
  tin01_c_hostvar   aHostVar;
  tin01_cstr        pNames;

  // init buffer 
  if (bSessionless) {
    i29_initadbs (session);
  } else {
    i29_initutility (session);
  } // end if

  // wirte command to buffer
  i29_pcmd (session, cmd, UNDEF_SP00);

  session->segment->sp1c_with_info () = true;
  session->segment->sp1c_producer ().becomes(sp1pr_internal_cmd);

  rc = i29_sqlrequest(session);

  if (rc == 0) {
    rc = i29_sqlreceive(session);

    if (rc != -8888) {

      // UTILITY commands always answer in ASCII
      tsp00_CodeType  code_type = session->code_type;
      session->code_type = csp_ascii;

      /* get some infos */
      pParamInfo  = i29gparaminfo(session, 0);
      nParamCount = i29paramcount(session);
      pNames      = i29colnames(session);

      i29_findpart (session, sp1pk_data);

      for (i = 0; i < nParamCount; i++) {

        if (pNames != 0) {
          nLen = *pNames++;
//          strncpy(pCurrent, pNames, nLen);
//          pCurrent += nLen;
          nOutLen = ((code_type == csp_unicode)||(code_type == csp_unicode_swap)) ? 
                           memcpyUCS2ToUTF8  (pCurrent, pNames, (int) nLen):
                           memcpyASCIIToASCII(pCurrent, pNames, (int) nLen);
          pCurrent += nOutLen;
          pNames   += nLen;
        } else {
          sprintf(pCurrent, "Field%d", i + 1);
          nLen = strlen(pCurrent);
          pCurrent += nLen;
        } // end if

        sprintf(pCurrent, "%*s= ", (nOutLen < 20 ? 20 - nOutLen : 1), " ");
        pCurrent += strlen(pCurrent);

        /* fill hostvar struct */
        memset(&aHostVar, 0, sizeof(aHostVar));
        aHostVar.len = -1;
        aHostVar.c_type.becomes(cin01_c_charp);
        memcpy(&(aHostVar.pinfo), &pParamInfo[i], sizeof(tsp1_param_info));
        aHostVar.addr = pCurrent;
        *pCurrent     = 0;

        /* read value */
        rc = i29_outarg (session, &aHostVar);

        /* check for <NULL> */
        if (aHostVar.is_null) {
          strcpy(pCurrent, cin29_nulltext);
        } /* end if */

        pCurrent += strlen(pCurrent);
        *pCurrent++ = '\n';

      } // end for 

       *pCurrent = 0;

      // reset codetype
      session->code_type = code_type;

    } // end if
  } // end if

  return rc;
} // end i29utilitynice


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

int i29utilcmd (
    tin01_sql_session * session,
    tin01_c_sqlca * sqlca,
    tin01_cstr cmd,
    ...)
{
    ROUTINE_DBG_MSP00 ("i29utilcmd");
    va_list         args;
    int             i;
    int             rc;
    int             paramCount;

    /* execute command */
    rc = i29utility (session, cmd);
    if (rc == cin01_db_ok) {
        /* get c variables addresses */
        va_start (args, cmd);
        for (i = 0; i < sqlca->varCount; ++i) {
            sqlca->hostVar[i].addr = va_arg (args, void *);
        }
        va_end (args);
        /* get sql parameter info */
        paramCount = i29paramcount (session);
        if (paramCount > sqlca->varCount)
            paramCount = sqlca->varCount;
/*            rc = -1200; */         /* too few values */
/*        else { */
            sqlca->paramCount = paramCount;
            if (paramCount > 0) {
                tsp1_param_info *pinfo = i29gparaminfo (session, 0);
                int              i;

                for (i = 0; i < paramCount; ++i, ++pinfo) {
                    memcpy (&sqlca->hostVar [i].pinfo, pinfo,
                            sizeof (tsp1_param_info));
                }
            }
            sqlca->inUse = true;
/*        } */

        // UTILITY commands always answer in ASCII
        tsp00_CodeType  code_type = session->code_type;
        session->code_type = csp_ascii;

        /* get sql parameters into c variables */
        if (rc == 0) {
            rc = i29_outargs (session, sqlca);
        }

        session->code_type = code_type;
    }
    return rc;
}

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

int i29utilbackuprequest (
    tin01_sql_session  * session,
    boolean              bBackupState,
    tin01_cstr           cmd)
{
    ROUTINE_DBG_MSP00 ("i29_utilbackuprequest");

    if (!bBackupState) {
        i29_initutility (session);
    } else {
        i29_initadbs (session);
    } /* end if */
    i29_pcmd (session, cmd, UNDEF_SP00);
    return i29_sqlrequest(session);
} /* end i29_utilbackuprequest */

/*----------------------------------------*/
int i29utilbackupreceive (
    tin01_sql_session  * session,
    tin01_c_sqlca      * sqlca,
    boolean            * bBackupRC,
    ...)
{
  ROUTINE_DBG_MSP00 ("i29_utilbackupreceive");
  va_list         args;
  int             i;
  int             rc;
  int             paramCount;

  rc = i29_sqlreceive(session);

  switch (rc) {
    case -7075:                       /* current save skipped           */
    case -7076:                       /* no more data to read from tape */
    case -8020:                       /* next volumn required           */
      *bBackupRC = true;
      break;
    default:
      *bBackupRC = false;
      break;
  } // end switch

  if (rc != -8888) {
    /* get c variables addresses */
    va_start (args, bBackupRC);
    for (i = 0; i < sqlca->varCount; ++i) {
      sqlca->hostVar[i].addr = va_arg (args, void *);
    } // end for
    va_end (args);

    /* get sql parameter info */
    paramCount = i29paramcount (session);
    if (paramCount > sqlca->varCount) {
      paramCount =  sqlca->varCount;
    } // end if

    sqlca->paramCount = paramCount;
    if (paramCount > 0) {
      tsp1_param_info *pinfo = i29gparaminfo (session, 0);
      int              i;

      for (i = 0; i < paramCount; ++i, ++pinfo) {
        memcpy (&sqlca->hostVar [i].pinfo, pinfo,
        sizeof (tsp1_param_info));
      } // end for
    } // end if

    sqlca->inUse = true;

    // SAVE/RESTORE commands always answer in ASCII
    tsp00_CodeType  code_type = session->code_type;
    session->code_type = csp_ascii;

    /* get sql parameters into c variables */
    if (rc == cin01_db_ok) {
      rc = i29_outargs (session, sqlca);
    } else {
      i29_outargs (session, sqlca);
    } // end if

    session->code_type = code_type;

  } // end if

  return rc;
} /* end i29_utilbackupreceive */

/*----------------------------------------*/
/**\
--- ----------------------------------MF__ MOD__ chapter communication
\**/
void i29pascalstring (
    char       *target,
    int         targetlen,
    const char *source,
    int         sourcelen)
{
    ROUTINE_DBG_MSP00 ("i29_pascalstring");
    if (source == NULL) {
        /* one blank so memcpy is ok */
        source = " ";
        sourcelen = 1;
    }
    else {
        if (sourcelen == -1)
            sourcelen = (int)strlen (source);
    }
    if (sourcelen > targetlen)
        memcpy (target, source, (int) targetlen);
    else {
        memcpy (target, source, (int) sourcelen);
        memset (target + sourcelen, ' ', (int) (targetlen - sourcelen));
    }
}

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

tin01_sql_session * i29lasterr_on (
    tin01_sql_session * session)
{
    ROUTINE_DBG_MSP00 ("i29_lasterr_on");
    session->lasterr.lasterr_on = true;
    return session;
} /* i29_lasterr_on */


/*----------------------------------------*/
int i29replyavailable (
    tin01_sql_session * session)
{
    ROUTINE_DBG_MSP00 ("i29_replyavailable");
    tsp00_ErrText     errtext;
    tsp01_CommErr  sp_rc;

    sqlareplyavailable (session->reference, errtext, &sp_rc);

    i29_setlasterr_rte (session, errtext, sp_rc) ;
    return sp_rc;
} /* end i29_replyavailable */

/*----------------------------------------*/
void i29cancel (
    tin01_sql_session * session)
{
    ROUTINE_DBG_MSP00 ("i29cancel");
    sqlacancel(session->reference);

} /* end i29_cancel */

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

void i29sqllasterr (
    tin01_sql_session     * session,
    tsp00_ErrTextc        & errtext,
    tsp00_KnlIdentifierc  & errname,
    tsp00_Int2            * errcode,
    tsp00_Int2            * errpos)
{
    ROUTINE_DBG_MSP00 ("i29_sqllasterr");
    * errpos = 0;
    *errcode = 0;
    memset(errtext, 0, sizeof(tsp00_ErrTextc));
    memset(errname, 0, sizeof(tsp00_KnlIdentifierc));
    if (session->lasterr.sp_rc != commErrOk_esp01) {
        memcpy (errtext, session->lasterr.errtext, sizeof (tsp00_ErrText));
        memcpy (errname, session->lasterr.errname, sizeof (tsp00_KnlIdentifier));
        *errcode = (tsp00_Int2) (session->lasterr.sp_rc + RTEERR_OFFSET);
        session->lasterr.sp_rc.becomes(commErrOk_esp01);
    }
    else if (session->lasterr.sqlresult.returnCode != cin01_db_ok) {
        *errcode = session->lasterr.sqlresult.returnCode;
        *errpos = session->lasterr.sqlresult.errorPos;
        memcpy (errtext, session->lasterr.sqlresult.sqlmsg, sizeof (tsp00_ErrText));
        memcpy (errname, session->lasterr.errname, sizeof (tsp00_KnlIdentifier));
        session->lasterr.sqlresult.returnCode = cin01_db_ok;
    }
    else {
        *errcode = 0;
        memset (errtext, ' ', sizeof (tsp00_ErrText));
        memset (errname, ' ', sizeof (tsp00_KnlIdentifier));
    }
}

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

int i29eventwait (
    tin01_sql_session       * session,
    tsp31_event_description * event)
{
  ROUTINE_DBG_MSP00 ("i29eventwait");

  int rc;

  // packet initialisieren
  i29_initspecial(session, sp1m_wait_for_event);

  // request absetzen und ins receive gehen
  rc = i29_sql (session, NULL);

  // struktur auswerten
  if (rc == cin01_db_ok) {
    if (i29_findpart (session, sp1pk_data)) {
      memcpy(event, session->part->sp1p_buf ().asCharp () + 1, sizeof(tsp31_event_description));
    } // end if
  } // end if

  return rc;
} /* end i29eventwait */


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

void i29release (
    tin01_sql_session * session,
    tin01_bool with_commit)
{
    ROUTINE_DBG_MSP00 ("i29release");
    int oldMode;

    oldMode = i29_adabasmode (session);
    IFDEBUG_MIN01 (i29_lasterr_off (session));
    IFDEBUG_MIN01 (i29_adbs_noinfo (session, "VTRACE"));
    i29_oldmode (session, oldMode);
    i29_lasterr_off (session);
    if (with_commit)
        i29_adbs_noinfo (session, "COMMIT WORK RELEASE");
    else
        i29_adbs_noinfo (session, "ROLLBACK WORK RELEASE");
    i29_cleanup_session (session);
}

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

void i29eventrelease (
    tin01_sql_session * session)
{
    ROUTINE_DBG_MSP00 ("i29eventrelease");

    i29_cleanup_session(session);
} // end i29eventrelease

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

void i29initsession (
    tin01_sql_session * session,
    tsp1_packet       * packet)
{
    ROUTINE_DBG_MSP00 ("i29_initsession");

    session->szDB.Init();
    session->szNode.Init();
    session->szUser.Init();
    session->szPwd.Init();
    session->reference       = 0;
    session->is_connected    = false;
    session->buildingCommand = false;
    i29_machinfo (&session->code_type, &session->swap_kind, session->senderid);
    i29_clearpacketref(session);
    session->sqlMode         = sp1sm_session_sqlmode;
    session->as_utility      = false;
} // end i29initsession

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

int i29paramcount (
    tin01_sql_session * pSession)
{
  ROUTINE_DBG_MSP00 ("i29paramcount");

  if (i29_findpart (pSession, sp1pk_shortinfo)) {
    return pSession->part->sp1p_arg_count ();
  } else {
    // currently, no hostvars -> no shortinfo part
    return 0;
  } // end if

} // end i29paramcount

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

tsp1_param_info * i29gparaminfo (
    tin01_sql_session * pSession,
    int                 nNumber)
{
  ROUTINE_DBG_MSP00 ("i29gparaminfo");

  if (i29_findpart (pSession, sp1pk_shortinfo)) {
    return ((tsp1_param_info *) (void*) pSession->part->sp1p_buf ()) + nNumber;
  } else {
    // currently, no hostvars -> no shortinfo part
    return NULL;
  } // end if

} // end i29gparaminfo

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

tin01_cstr i29colnames (
    tin01_sql_session * session)
{
    ROUTINE_DBG_MSP00 ("i29colnames");
    if (i29_findpart (session, sp1pk_columnnames)) {
      return session->part->sp1p_buf ().asCharp ();
    } else {
      return NULL;
    }// end if
} // end i29colnames

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

int i29adbs (
    tin01_sql_session * session,
    tin01_cstr cmd)
{
    ROUTINE_DBG_MSP00 ("i29adbs");
    i29_initadbs (session);
    session->segment->sp1c_with_info () = true;
    i29_pcmd (session, cmd, UNDEF_SP00);
    return i29_sql (session, NULL);
} // end i29adbs

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

int i29sqlcmd (
    tin01_sql_session * session,
    tin01_c_sqlca * sqlca,
    tin01_cstr cmd,
    ...)
{
    ROUTINE_DBG_MSP00 ("i29sqlcmd");
    va_list         args;
    int             rc;
    int             trycnt = 0;
    tin01_bool      try_again = true;
    int             i;

    do {
        rc = i29_parse (session, cmd, sqlca, false);
        if (rc == cin01_db_ok) {
            va_start (args, cmd);
            for (i = 0; i < sqlca->varCount; ++i) {
                sqlca->hostVar[i].addr = va_arg (args, void *);
            }
            va_end (args);
            rc = i29_inargs (session, sqlca);
            if (rc == cin01_db_ok)
                rc = i29_sql (session, NULL);
            if (rc == cin01_db_ok) {
                rc = i29_outargs (session, sqlca);
            }
        }
        if (i29_try_again (rc)) {
            try_again = true;
            sqlca->inUse = false;
        }
        else
            try_again = false;
        ++trycnt;
    }
    while (try_again && (trycnt < c_max_try));
    return rc;
} // i29sqlcmd

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

void i29errmsg (
    tin01_sql_session * session,
    tsp00_C256c       & errbuf)
{
    ROUTINE_DBG_MSP00 ("i29errmsg");

    errbuf[0] = '\0';

    if (session->rec_packet != NULL) {
      if (session->segment->sp1r_returncode () != cin01_db_ok) {

        if (i29_findpart(session, sp1pk_errortext)) {
          if (IS_UNICODE(session)) {
            memcpyUCS2ToUTF8  (errbuf.asCharp(), session->part->sp1p_buf ().asCharp (), session->part->sp1p_buf_len (), true, errbuf.size() - 1);
          } else {
            memcpyASCIIToASCII(errbuf.asCharp(), session->part->sp1p_buf ().asCharp (), session->part->sp1p_buf_len (), true, errbuf.size() - 1);
          } // end if

          errbuf[s30klen (errbuf.asCharp(), ' ', errbuf.length())] = '\0';
        } /* end if */
      } /* end if */
    } else {
      if (session->lasterr.lasterr_on) {
          size_t minlen=errbuf.size();

          if(minlen>sizeof(tsp00_ErrText)-1)
              minlen=sizeof(tsp00_ErrText)-1;

        memcpy((char *)errbuf, session->lasterr.errtext, minlen);
        errbuf[minlen] = '\0';
      } /* end if */
    } /* end if */

} /* end i29errmsg */

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

int i29usrconnect (
     tin01_sql_session       * pSession,
     const char              * szDB,
     const char              * szNode,
     const char              * szUsr,
     const char              * szPwd,
     bool                      bUnicode,
     bool                      bUtility)
{
  size_t i = 0;
  size_t j = 0;
  bool bUpper = true;

  // task type
  pSession->as_utility = bUtility;

  // code type
  if (bUnicode && pSession->swap_kind == sw_normal) {
    pSession->code_type = csp_unicode;
  } else if (bUnicode)  {
    pSession->code_type = csp_unicode_swap;
  } // end uf

  // database
  pSession->szDB.rawAssign(szDB);

  // node
  pSession->szNode.rawAssign(szNode);

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

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

  // and connect
  return i29reconnect(pSession);

} // end i29usrconnect

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

int i29eventconnect (
    tin01_sql_session        * pSession,
    const char               * szDB,
    bool                       bUnicode)
{
    ROUTINE_DBG_MSP00 ("i29eventconnect");

    tsp01_Service       connectKind;

    connectKind.becomes(srvEvent_esp01);

    // code type
    if (bUnicode && pSession->swap_kind == sw_normal) {
      pSession->code_type = csp_unicode;
    } else if (bUnicode)  {
      pSession->code_type = csp_unicode_swap;
    } // end uf

    // database
    pSession->szDB.rawAssign(szDB);

    return i29_connect( pSession, connectKind);
} /* end i29eventconnect */

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

int i29reconnect (
    tin01_sql_session * session)
{
  ROUTINE_DBG_MSP00 ("i29reconnect");

  int                 connect_rc;
  tsp01_Service       connectKind;
  tsp00_TermId        termid;

  if (session->as_utility) {
    connectKind.becomes(srvUtility_esp01);
  } else {
    connectKind.becomes(srvUser_esp01);
  } // end if

  if (i29_connect( session, connectKind) == commErrOk_esp01) {
    
    sqltermid (termid);
    i29_connectcommand (session, termid);
    connect_rc = i29_sql (session, NULL);
    if (connect_rc != cin01_db_ok) {
      sqlarelease (session->reference);
      session->is_connected = false;
      TRACEF_MIN01 (5, (SQLTRACE, "Connect command failed with %d\n", (int) connect_rc));
    } else {
      // read session info part
      if (i29_findpart(session, sp1pk_session_info_returned)) {
        if (session->part->sp1p_buf()[0] == 1) {
          if (session->swap_kind == sw_normal) {
            session->code_type = csp_unicode;
          } else {
            session->code_type = csp_unicode_swap;
          } // end uf
        } // end if

      } // end if
    } // end if
    return connect_rc;
  } // end if
  return commErrNotOk_esp01;
} // end i29reconnect
