/* Bbuuzzb low level session table management module.
   Rick Smereka, Copyright (C) 2001-2004.

   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, get a copy via the Internet at
   http://gnu.org/copyleft/gpl.html or write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston,
   MA 02111-1307 USA

   You can contact the author via email at rsmereka@future-lab.com

   Original QNX version. Oct/2001, Rick Smereka

   Ported to Linux and Windows 32bit. Nov/2001, Rick Smereka

   Added support for the new commands 'DBENG_SEND_GET_NSUBFIELDS',
   'DBENG_SEND_GET_SUBFIELD_SIZE', DBENG_SEND_GET_SUBFIELD',
   'DBENG_SEND_PUT_SUBFIELD', 'DBENG_SEND_GET_NSUBSUBFIELDS',
   'DBENG_SEND_GET_SUBSUBFIELD_SIZE', 'DBENG_SEND_GET_SUBSUBFIELD'
   and 'DBENG_SEND_PUT_SUBSUBFIELD' in the function
   'dbeng_session_should_rs'. Jan/2002, Rick Smereka

   Changed function 'dbeng_session_open' to open the session table
   using 'dbeng_open_systable'. Feb/2002, Rick Smereka

   Added support for the command 'DBENG_SEND_REPLICATE_UPDATE'.
   Mar/2002, Rick Smereka

   Changed function 'dbeng_session_flush_all' to call
   'dbeng_clear_table' to clear the session table.
   Jun/2002, Rick Smereka

   Added support for the commands 'DBENG_SEND_SORT',
   'DBENG_SEND_GET_SORT_MEM', 'DBENG_SEND_SET_SORT_MEM',
   'DBENG_SEND_GET_SORT_OPEN_BIN' and 'DBENG_SEND_SET_SORT_OPEN_BIN'
   in the function 'dbeng_session_should_rs'.  Ported to Debian
   Linux. Nov/2002, Rick Smereka

   Added support for the commands 'DBENG_SEND_DELETE_FIELD',
   'DBENG_SEND_DELETE_SUBFIELD' and 'DBENG_SEND_DELETE_SUBSUBFIELD'
   in the function 'dbeng_session_should_rs'. Mar/2003, Rick Smereka

   Added support for the send codes 'DBENG_SEND_TRANS_NUM' and
   'DBENG_SEND_CONNECT_NUM' in the function 'dbeng_session_should_rs'.
   Jun/2003, Rick Smereka

   Added support for the send codes 'DBENG_SEND_GET_AUTOPACK' and
   'DBENG_SEND_SET_AUTOPACK' in the function 'dbeng_session_should_rs'.
   Changed all logging calls from 'sys_log' to 'logman'.
   Mar/2004, Rick Smereka

   Added support for the send code 'DBENG_SEND_SET_LOG' in the function
   'dbeng_session_should_rs'. Apr/2004, Rick Smereka */

#include "stdhead.h"
#include "dbeng.h"
#include "dbmess.h"
#include "dbengcfg.h"
#include "dbengses.h"

/* global data */

struct dbeng_table *st = DBENG_OT_NULL;
int dbengses_deleted = 0;

/* private functions */

static int dbeng_session_open(void);
static int dbeng_session_close(void);
static int dbeng_session_del_rec(struct dbeng_table *);

int dbeng_session_save(int tid)
{
   /* Save the information on the table 'tid'. The file will be closed
      and the current record data (if any) will be saved to the
      system session table. Function returns 'DBENG_OK' upon success,
      an engine i/o code otherwise. */

   struct dbeng_table *ot;
   char mname[] = "dbeng_session_save", *trec, *crec;
   int rec_size, ret;

   if (tid <= 0)
      {
      dbeng_io_code_log(mname, "out of range[tid]", DBENG_INVALID_FUNCTION);
      return(DBENG_INVALID_FUNCTION);
      }

   ot = dbeng_atid_lookup(tid);

   if (ot == DBENG_OT_NULL)
      {
      dbeng_io_code_log(mname, "null 'ot'", DBENG_INVALID_FUNCTION);
      return(DBENG_INVALID_FUNCTION);
      }

   logman("%s:enter:name=%s,tid=%d", mname, ot->name, ot->tid);

   /* open the session table */

   if ((ret = dbeng_session_open()) != DBENG_OK)
      {
      dbeng_io_code_log(mname, "exit:bad ret code from dbeng_session_open",
                        ret);
      return(ret);
      }

   /* if there is a record in memory, save it */

   if (dbeng_is_active_rec(ot) == DBENG_OK)
      {
      /* get size of record in memory */

      if ((ret = dbeng_rec_size(ot, &rec_size)) != DBENG_OK)
         {
         dbeng_io_code_log(mname, "exit:unable to get size of "
                           "table rec", ret);
         (void)dbeng_session_close();
         return(ret);
         }

      /* get contents of record in memory */

      if ((crec = (char *)malloc(rec_size + 1)) == (char *)NULL)
         {
         dbeng_io_code_log(mname, "exit:alloc fail crec", DBENG_MEMORY_FAIL);
         (void)dbeng_session_close();
         return(DBENG_MEMORY_FAIL);
         }

      if ((ret = dbeng_get_rec(ot, crec)) != DBENG_OK)
         {
         free(crec);
         dbeng_io_code_log(mname, "exit:bad ret from dbeng_get_rec", ret);
         (void)dbeng_session_close();
         return(ret);
         }

      /* build sesson record with field one as the tid */

      if ((trec = (char *)malloc(rec_size + 12)) == (char *)NULL)
         {
         free(crec);
         dbeng_io_code_log(mname, "exit:alloc fail trec", DBENG_MEMORY_FAIL);
         (void)dbeng_session_close();
         return(DBENG_MEMORY_FAIL);
         }

      sprintf(trec, "%d%c%s", tid, DBENG_FM, crec);
      free(crec);

      /* write session record */

      ret = dbeng_write_string_recd(st, trec);

      /* de-allocate memory for record contents */

      free(trec);
      free(ot->rec);
      ot->rec = (char *)NULL;
      }

   (void)dbeng_ll_close(ot);    /* close table */
   (void)dbeng_session_close(); /* close session table */
   dbeng_io_code_log(mname, "normal exit", ret);
   return(ret);
}

int dbeng_session_restore(int tid)
{
   /* Restore the information on the table 'tid'. The file will be opened
      and the current record data (if any) will be restored from the
      system session table. Function returns 'DBENG_OK' upon success,
      an engine i/o code otherwise. */

   struct dbeng_table *ot;
   char mname[] = "dbeng_session_restore", *crec;
   char tmp[15];
   int rec_size, indx, ret;

   if (tid <= 0)
      {
      dbeng_io_code_log(mname, "out of range[tid]", DBENG_INVALID_FUNCTION);
      return(DBENG_INVALID_FUNCTION);
      }

   ot = dbeng_atid_lookup(tid);

   if (ot == DBENG_OT_NULL)
      {
      dbeng_io_code_log(mname, "null 'ot'", DBENG_INVALID_FUNCTION);
      return(DBENG_INVALID_FUNCTION);
      }

   logman("%s:enter:tid=%d", mname, ot->tid);

   /* open the session table */

   if ((ret = dbeng_session_open()) != DBENG_OK)
      {
      dbeng_io_code_log(mname, "bad return from dbeng_session_open", ret);
      return(ret);
      }

   /* search for saved session record */
   
   sprintf(tmp, "%d", ot->tid);   
   ret = dbeng_find_field(st, 0, tmp, 1);
   
   /* if record was found, load into table 'rec' and
      delete the record from the session table */
      
   if (ret == DBENG_OK)
      {
      /* get the size of the session table record */
      
      if ((ret = dbeng_rec_size(st, &rec_size)) != DBENG_OK)
         {
         dbeng_io_code_log(mname, "exit:bad ret from dbeng_rec_size", ret);
         (void)dbeng_session_close();
         return(ret);
         }
         
      /* get session table record contents */
      
      if ((crec = (char *)malloc(rec_size + 1)) == (char *)NULL)
         {
         dbeng_io_code_log(mname, "exit:alloc fail crec", DBENG_MEMORY_FAIL);
         (void)dbeng_session_close();
         return(DBENG_MEMORY_FAIL);
         }
         
      if ((ret = dbeng_get_rec(st, crec)) != DBENG_OK)
         {
         free(crec);
         dbeng_io_code_log(mname, "exit:bad ret from dbeng_get_rec", ret);
         (void)dbeng_session_close();
         return(ret);
         }
      
      /* resize actual table record and re-load */
      
      if ((ret = dbeng_rec_resize(ot, rec_size)) != DBENG_OK)
         {
         free(crec);
         dbeng_io_code_log(mname, "exit:bad ret from dbeng_rec_resize", ret);
         (void)dbeng_session_close();
         return(ret);
         }
         
      /* copy session table record to table record minus the first 
         field (which is the tid */

      indx = ll_indxword(crec, 2, DBENG_FM);
      strcpy(ot->rec, &crec[indx]);
      free(crec);

      /* delete session table record */

      if ((ret = dbeng_session_del_rec(ot)) != DBENG_OK)
         {
         dbeng_io_code_log(mname, "exit:bad ret from dbeng_session_del_rec", 
                           ret);
         (void)dbeng_session_close();
         return(ret);
         }
      }
      
   (void)dbeng_session_close();
   (void)dbeng_ll_open(ot);
   dbeng_io_code_log(mname, "normal exit", DBENG_OK);
   return(DBENG_OK);
}

int dbeng_session_delete(int tid)
{
   /* Delete the active session record by 'tid'.
      Function returns a 'dbeng' code. */

   struct dbeng_table *ot;
   char mname[] = "dbeng_session_delete";
   int ret;

   logman("%s:enter", mname);

   if (tid <= 0)
      {
      dbeng_io_code_log(mname, "out of range[tid]", DBENG_INVALID_FUNCTION);
      return(DBENG_INVALID_FUNCTION);
      }

   if ((ret = dbeng_session_open()) != DBENG_OK)
      {
      dbeng_io_code_log(mname, "bad rc from dbeng_sesson_open", ret);
      return(ret);
      }

   ot = dbeng_atid_lookup(tid);

   if (ot == DBENG_OT_NULL)
      {
      dbeng_io_code_log(mname, "null 'ot'", DBENG_INVALID_FUNCTION);
      return(DBENG_INVALID_FUNCTION);
      }

   if ((ret = dbeng_session_del_rec(ot)) != DBENG_OK)
      dbeng_io_code_log(mname, "bad rc from dbeng_session_del_rec", ret);

   if ((ret = dbeng_session_close()) != DBENG_OK)
      dbeng_io_code_log(mname, "bad rc from dbeng_session_close", ret);

   return(ret);
}

int dbeng_session_should_rs(int mestype, char *comm, int *tid)
{
   /* Determine whether record data should be restored and then
      saved based on the send code. Function returns 'TRUE' if
      the restore and save operations should be performed along
      with the table 'tid'. Function returns 'FALSE' otherwise. */

   char *tid_char, mname[] = "dbeng_session_should_rs";
   int should_rs;

   logman("%s:enter:mestype=%d", mname, mestype);
   *tid = 0;

   /* set flag based on send code */

   switch(mestype)
      {
      case DBENG_SEND_OPEN:
         should_rs = FALSE;
         break;

      case DBENG_SEND_CLOSE:
         should_rs = FALSE;
         break;

      case DBENG_SEND_NEXT:
         should_rs = TRUE;
         break;

      case DBENG_SEND_TOP:
         should_rs = TRUE;
         break;

      case DBENG_SEND_GET_REC:
         should_rs = TRUE;
         break;

      case DBENG_SEND_GET_REC_SIZE:
         should_rs = TRUE;
         break;

      case DBENG_SEND_GET_FIELD_SIZE:
         should_rs = TRUE;
         break;

      case DBENG_SEND_GET_FIELD:
         should_rs = TRUE;
         break;

      case DBENG_SEND_GOTO:
         should_rs = TRUE;
         break;

      case DBENG_SEND_PUT_FIELD:
         should_rs = TRUE;
         break;

      case DBENG_SEND_WRITE:
         should_rs = TRUE;
         break;

      case DBENG_SEND_DELETE:
         should_rs = TRUE;
         break;

      case DBENG_SEND_GET_NFIELDS:
         should_rs = TRUE;
         break;

      case DBENG_SEND_GET_REC_NUM:
         should_rs = FALSE;
         break;

      case DBENG_SEND_GET_DELETE_FLAG:
         should_rs = FALSE;
         break;

      case DBENG_SEND_SET_DELETE_FLAG:
         should_rs = FALSE;
         break;

      case DBENG_SEND_COUNT:
         should_rs = TRUE;
         break;

      case DBENG_SEND_PACK:
         should_rs = TRUE;
         break;

      case DBENG_SEND_FIND:
         should_rs = TRUE;
         break;

      case DBENG_SEND_FIND_FIELD:
         should_rs = TRUE;
         break;

      case DBENG_SEND_FIND_PART:
         should_rs = TRUE;
         break;

      case DBENG_SEND_FIND_FIELD_PART:
         should_rs = TRUE;
         break;

      case DBENG_SEND_GET_POS:
         should_rs = FALSE;
         break;

      case DBENG_SEND_SET_POS:
         should_rs = TRUE;
         break;

      case DBENG_SEND_GET_CHANGE_REC_FLAG:
         should_rs = TRUE;
         break;

      case DBENG_SEND_SET_CHANGE_REC_FLAG:
         should_rs = TRUE;
         break;

      case DBENG_SEND_NEW:
         should_rs = TRUE;
         break;

      case DBENG_SEND_GET_REC_COUNT:
         should_rs = FALSE;
         break;

      case DBENG_SEND_GET_ENF_CHANGE_REC_FLAG:
         should_rs = FALSE;
         break;

      case DBENG_SEND_SET_ENF_CHANGE_REC_FLAG:
         should_rs = FALSE;
         break;

      case DBENG_SEND_GET_IS_TABLE_LOCKED:
         should_rs = FALSE;
         break;

      case DBENG_SEND_SET_IS_TABLE_LOCKED:
         should_rs = FALSE;
         break;

      case DBENG_SEND_STATUS:
         should_rs = FALSE;
         break;

      case DBENG_SEND_NEW_TABLE:
         should_rs = FALSE;
         break;
      
      case DBENG_SEND_GET_TMP_PATH:
         should_rs = FALSE;
         break;

      case DBENG_SEND_GET_LOG:
         should_rs = FALSE;
         break;

      case DBENG_SEND_GET_SESSION:
         should_rs = FALSE;
         break;

      case DBENG_SEND_GET_CATALOG:
         should_rs = FALSE;
         break;

      case DBENG_SEND_GET_LOG_FLAG:
         should_rs = FALSE;
         break;
         
      case DBENG_SEND_GET_SESSION_FLAG:
         should_rs = FALSE;
         break;
         
      case DBENG_SEND_GET_CATALOG_FLAG:
         should_rs = FALSE;
         break;

      case DBENG_SEND_GET_DBENG_VERSION:
         should_rs = FALSE;         
         break;
                  
      case DBENG_SEND_SET_TMP_PATH:
         should_rs = FALSE;
         break;

      case DBENG_SEND_SET_SESSION:
         should_rs = FALSE;
         break;

      case DBENG_SEND_SET_CATALOG:
         should_rs = FALSE;
         break;
         
      case DBENG_SEND_SET_LOG_FLAG:
         should_rs = FALSE;
         break;
         
      case DBENG_SEND_SET_SESSION_FLAG:
         should_rs = FALSE;
         break;
         
      case DBENG_SEND_SET_CATALOG_FLAG:
         should_rs = FALSE;
         break;
                     
      case DBENG_SEND_TERM:
         should_rs = FALSE;
         break;

      case DBENG_SEND_LOG_OFF:
         should_rs = FALSE;         
         break;

      case DBENG_SEND_LOG_ON:
         should_rs = FALSE;         
         break;

      case DBENG_SEND_LOG_STATUS:
         should_rs = FALSE;
         break;

      case DBENG_SEND_SERVICE_NAME:
         should_rs = FALSE;
         break;

      case DBENG_SEND_VERSION:
         should_rs = FALSE;         
         break;

      case DBENG_SEND_GET_OPEN_TABLE_LIST:
      case DBENG_SEND_GET_CATALOG_LIST:
         should_rs = FALSE;
         break;

      case DBENG_SEND_GET_NSUBFIELDS:
      case DBENG_SEND_GET_SUBFIELD_SIZE:
      case DBENG_SEND_GET_SUBFIELD:
      case DBENG_SEND_PUT_SUBFIELD:
      case DBENG_SEND_GET_NSUBSUBFIELDS:
      case DBENG_SEND_GET_SUBSUBFIELD_SIZE:
      case DBENG_SEND_GET_SUBSUBFIELD:
      case DBENG_SEND_PUT_SUBSUBFIELD:
      case DBENG_SEND_COPY_TABLE:
      case DBENG_SEND_SORT:
      case DBENG_SEND_DELETE_FIELD:
      case DBENG_SEND_DELETE_SUBFIELD:
      case DBENG_SEND_DELETE_SUBSUBFIELD:
         should_rs = TRUE;
         break;

      case DBENG_SEND_REPLICATE:
      case DBENG_SEND_GET_REPLICATE_FLAG:
      case DBENG_SEND_SET_REPLICATE_FLAG:
      case DBENG_SEND_REPLICATE_UPDATE:
      case DBENG_SEND_DELETE_TABLE:
      case DBENG_SEND_EXIST:
      case DBENG_SEND_CLEAR_TABLE:
      case DBENG_SEND_GET_SORT_MEM:
      case DBENG_SEND_SET_SORT_MEM:
      case DBENG_SEND_GET_SORT_OPEN_BIN:
      case DBENG_SEND_SET_SORT_OPEN_BIN:
      case DBENG_SEND_TRANS_NUM:
      case DBENG_SEND_CONNECT_NUM:
      case DBENG_SEND_GET_AUTOPACK:
      case DBENG_SEND_SET_LOG:
         should_rs = FALSE;
         break;

      default:
         logman("%s:received unknown code[%d]", mname, mestype);
         should_rs = FALSE;
         break;
      };

   if (should_rs)
      {
      if ((tid_char = (char *)malloc(strlen(comm) + 1)) == (char *)NULL)
         {
         dbeng_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
         return(FALSE);
         }

      (void)word(comm, tid_char, 1);
      
      if (!qatoi(tid_char, tid))
         {
         free(tid_char);
         dbeng_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
         return(FALSE);
         }

      free(tid_char);

      if (*tid <= 0)
         {
         dbeng_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
         return(FALSE);
         }
      }

   logman("%s:normal exit[%d]", mname, should_rs);
   return(should_rs);
}

int dbeng_session_flush_all(void)
{
   /* Empty the session table. All records will be removed by
      deleting the table and re-creating it. Function returns
      a 'dbeng' code. */

   char mname[] = "dbeng_session_flush_all";
   char *ses_table;
   int ret;

   logman("%s:enter", mname);

   /* make sure session table is not open */

   if (st != DBENG_OT_NULL)
      {
      dbeng_io_code_log(mname, "session table open",
                        DBENG_INVALID_FUNCTION);
      return(DBENG_INVALID_FUNCTION);
      }

   if ((ses_table = (char *)malloc(DBENG_PATH_LIMIT)) == (char *)NULL)
      {
      dbeng_io_code_log(mname, "alloc fail[ses_table]", DBENG_MEMORY_FAIL);
      return(DBENG_MEMORY_FAIL);
      }
   
   /* get session table name */
   
   if ((ret = dbeng_config_get_session(ses_table)) != DBENG_OK)
      {
      dbeng_io_code_log(mname, "bad ret from dbeng_config_get_session",
                        ret);
      free(ses_table);
      return(ret);
      }

   if ((ret = dbeng_clear_table(ses_table)) != DBENG_OK)
      {
      dbeng_io_code_log(mname, "bad ret from dbeng_clear_table", ret);
      free(ses_table);
      return(ret);
      }

   free(ses_table);
   dbeng_io_code_log(mname, "normal exit", DBENG_OK);
   return(DBENG_OK);
}

/* private functions */

static int dbeng_session_open(void)
{
   /* Open the system session table. Note that the table pointer
      is stored in the global 'st'. */

   char mname[] = "dbeng_session_open";
   char *ses_table;
   int tid, ret;

   logman("%s:enter", mname);

   /* make sure session table is not already open */

   if (st != DBENG_OT_NULL)
      {
      dbeng_io_code_log(mname, "session table already open",
                        DBENG_INVALID_FUNCTION);
      return(DBENG_INVALID_FUNCTION);
      }

   if ((ses_table = (char *)malloc(DBENG_PATH_LIMIT)) == (char *)NULL)
      {
      dbeng_io_code_log(mname, "alloc fail[ses_table]", DBENG_MEMORY_FAIL);
      return(DBENG_MEMORY_FAIL);
      }
   
   /* get session table name */
   
   if ((ret = dbeng_config_get_session(ses_table)) != DBENG_OK)
      {
      dbeng_io_code_log(mname, "bad ret from dbeng_config_get_session",
                        ret);
      free(ses_table);
      return(ret);
      }
      
   ret = dbeng_open_systable(ses_table, &tid);
   free(ses_table);

   if (ret != DBENG_OK)
      {
      dbeng_io_code_log(mname, "exit:unable to open system session table", ret);
      return(ret);
      }

   /* get pointer to now opened session table */

   if ((st = dbeng_atid_lookup(tid)) == DBENG_OT_NULL)
      {
      dbeng_io_code_log(mname, "exit:dbeng_atid_lookup error on session table",
                        DBENG_UNABLE_TO_OPEN);
      return(DBENG_UNABLE_TO_OPEN);
      }

   dbeng_io_code_log(mname, "normal exit", DBENG_OK);
   return(DBENG_OK);
}

static int dbeng_session_close(void)
{
   /* Close the session table and set the global 'st' to NULL. */

   char mname[25];
   int ret;

   strcpy(mname, "dbeng_session_close");
   logman("%s:enter", mname);
   
   if (st == DBENG_OT_NULL)
      {
      dbeng_io_code_log(mname, "exit:session table not open", DBENG_NO_SUCH_FILE);
      return(DBENG_NO_SUCH_FILE);
      }

   ret = dbeng_close_table(st);
   st = DBENG_OT_NULL;
   dbeng_io_code_log(mname, "normal exit", ret);
   return(ret);
}

static int dbeng_session_del_rec(struct dbeng_table *ot)
{
   /* Delete any exisiting system session record for 'ot'.
      The system session table is assumed to be open with
      the table pointer loaded into 'st'. Function returns
      a 'dbeng' engine code. */

   char tid_char[15];
   char mname[] = "dbeng_session_del_rec";
   int ret;

   logman("%s:enter", mname);

   if (ot == DBENG_OT_NULL)
      {
      dbeng_io_code_log(mname, "exit:null ot", DBENG_INVALID_FUNCTION);
      return(DBENG_INVALID_FUNCTION);
      }

   if (st == DBENG_OT_NULL)
      {
      dbeng_io_code_log(mname, "exit:session table not open",
                        DBENG_INVALID_FUNCTION);
      return(DBENG_INVALID_FUNCTION);
      }

   /* since we could be anywhere in the session table, we
      will goto the top of the table */
      
   if ((ret = dbeng_goto_top(st)) != DBENG_OK)
      {
      dbeng_io_code_log(mname, "exit:error going to top of session table", ret);
      return(ret);
      }
      
   sprintf(tid_char, "%d", ot->tid);

   /* locate any previous record based on this tid from the session table */

   ret = dbeng_find_field(st, 0, tid_char, 1);

   /* if record was found, delete it */

   if (ret == DBENG_OK)
      {
      if ((ret = dbeng_delete_recd(st)) != DBENG_OK)
         {
         dbeng_io_code_log(mname, "exit:error deleting prev session table rec", ret);
         return(ret);
         }
      else
         {
         dbengses_deleted++;

         /* check for max number of deleted records in session table
            and pack if necessary */

         if ((dbengses_deleted % DBENGSES_MAX_DELETED) == 0)
            {
            logman("%s:max deleted session records exceeded[%d],"
                          "packing", mname, dbengses_deleted);

            if ((ret = dbeng_pack_table(st)) != DBENG_OK)
               dbeng_io_code_log(mname, "session table pack error", ret);
            }
         }    
      }
   else
      if (ret != DBENG_EOF)
         {
         dbeng_io_code_log(mname, "exit:error finding prev session table rec", ret);
         return(ret);
         }   
         
   dbeng_io_code_log(mname, "normal exit", ret);
   return(ret);
}
