## root/source/dbstress.c

/* [<][>][^][v][top][bottom][index][help] */

## DEFINITIONS

This source file includes following definitions.

1. main
2. parse_comline
3. c_initialize
4. c_initialize
5. c_ipc_socloc_init
6. check_files
7. pick_com
8. do_com
9. c_open
10. c_close
11. c_next
12. c_top
13. c_get_rec
14. c_get_field
15. c_get_subfield
16. c_get_subsubfield
17. c_get_rec_size
18. c_get_field_size
19. c_get_subfield_size
20. c_get_subsubfield_size
21. c_goto
22. c_count
23. c_put_field
24. c_put_subfield
25. c_put_subsubfield
26. c_write
27. c_delete
28. c_get_delete_flag
29. c_set_delete_flag
30. c_get_nfields
31. c_get_nsubfields
32. c_get_nsubsubfields
33. c_get_rec_num
34. c_get_pos
35. c_get_change_rec_flag
36. c_set_change_rec_flag
37. c_pack
38. c_new
39. c_find
40. c_find_field
41. c_find_part
42. c_find_field_part
43. c_get_rec_count
44. c_get_enf_change_rec_flag
45. c_set_enf_change_rec_flag
46. c_get_is_table_locked
47. c_set_is_table_locked
48. c_new_table
49. c_config_get_tmp_path
50. c_config_get_log
51. c_config_get_session
52. c_config_get_catalog
53. c_config_get_log_flag
54. c_config_get_session_flag
55. c_config_get_catalog_flag
56. c_config_get_replicate_flag
57. c_config_get_version
58. c_get_open_table_list
59. c_version
60. c_exist
61. c_get_catalog_list
62. c_sort
63. c_get_sort_mem
64. c_set_sort_mem
65. c_get_sort_open_bin
66. c_set_sort_open_bin
67. c_delete_field
68. c_delete_subfield
69. c_delete_subsubfield
70. c_trans_num
71. c_connect_num
72. c_get_autopack
73. c_set_autopack
74. c_config_client_get_log
75. c_config_client_get_log_flag
76. c_put_data
77. term_app

    /* dbstress: A program to stress test the database engine 'Bbuuzzb'.
       Program picks a random number which represents a command type and
       then executes that command. Program is an infinite loop and will
       have to be killed to terminate. Command numbers are taken from
       'dbcomm.h'. Rick Smereka, Copyright (C) 1997-2006.

       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 DOS version Nov/97, Rick Smereka

       Added transaction number, program logo to log file and client/server
       version. Ported to QNX V4.23a Dec/97, Rick Smereka

       Added support for the table 'is_table_locked' flag. Jan/98,
       Rick Smereka

       Added #include's for 'dblocal' and 'dbiocode' as they
       were missing. Nov/98, Rick Smereka

       Ported to 32bit Windows under CodeWarrior V4.
       Dec/98, Rick Smereka

       Ported to HP-UX under GNU C 2.8.1.
       Jan/99, Rick Smereka

       Ported to Red Hat Linux 5.2, Jul/99, Rick Smereka

       Updated to include new (mostly configuration) commands. Program will
       not process all commands as some are just too dangerous. The following
       commands will be ignored:

          DBCOM_SET_POS               set file position
          DBCOM_CONFIG_SET_TMP_PATH   set config path for temporary files
          DBCOM_CONFIG_SET_LOG        set config error log file
          DBCOM_CONFIG_SET_SESSION    set config session table (multi only)
          DBCOM_CONFIG_SET_CATALOG    set config catalog table (multi only)

       When these commands are chosen, an 'unknown command' message will
       appear in the output log. Aug/99, Rick Smereka

       Re-compiled after re-structuring the definition of the common
       send and repy codes. Moved 'include' of the header 'flsocket.h'
       inside the 'MULTIUSER' if statement. Modified to use the
       'socloc' API if in multiuser mode. Changed 'c_config_set_log_flag'
       to turn logging back on if it was turned off. Added command line
       parameters to specify the primary and alternate table names as well
       as the log file name. Program syntax is now:

       dbstress|dbstresm [-p primary_table] [-a alternate_table] [-l log_file]

       Where '-p primary_table' is the optional name of the Bbuuzzb primary
       table to use, '-a alternate_table' is the alternate table and
       '-l log_file' is the log file to use. Any of these three items
       will default to their defined values if not present on the command
       line. Note that the switch character ('-') is based on the platform
       (see include file 'stdhead.h'). Apr/2000, Rick Smereka

       Re-compiled after adding the new 'clib' module 'ip.c'.
       Jul/2000, Rick Smereka

       Added support for the new command 'get_open_table_list'.
       Re-compiled for new database engine version. Jun/2001,
       Rick Smereka

       Modified for use with both sockets and QNX message passing IPC.
       Oct/2001, Rick Smereka

       Removed support for the following commands:

          DBCOM_CONFIG_SET_LOG_FLAG
          DBCOM_CONFIG_SET_SESSION_FLAG
          DBCOM_CONFIG_SET_CATALOG_FLAG

       It is assumed that these will be set on the database server prior
       to running this program and the values will not be changed during
       the course of this program run.

       Modified to use system catalog in the client/sever version.
       The default table names have been changed to the logical names:

          test.primary
          test.alternate

       When supplying table names on the command line, use logical names
       if the server catalog is operational. Nov/2001, Rick Smereka

       Added support of the new database commands 'DBCOM_GET_NSUBFIELDS',
       'DBCOM_GET_NSUBFIELD_SIZE', 'DBCOM_GET_SUBFIELD', 'DBCOM_PUT_SUBFIELD',
       'DBCOM_GET_NSUBSUBFIELDS', 'DBCOM_GET_NSUBSUBFIELD_SIZE',
       'DBCOM_GET_SUBSUBFIELD', 'DBCOM_PUT_SUBSUBFIELD',
       'DBCOM_CONFIG_GET_REPLICATE_FLAG'. Excluded
       'DBCOM_CONFIG_SET_REPLICATE_FLAG'. This should be set on the
       database server prior to executing this program. Added log
       output of current record position before command is executed.
       Jan/2002, Rick Smereka

       Excluded the include of 'flsocket.h' in the case of DOS.
       Apr/2002, Rick Smereka

       Added support for automatic field, subfield and subsubfield
       append using the value zero. Functions 'c_put_field',
       'c_put_subfield' and 'c_put_subsubfield' now generate zero
       values (in the field, subfield and subsubfield number parameter)
       to signify an append. May/2002, Rick Smereka

       Added support for the commands 'DBCOM_EXIST', 'DBCOM_GET_CATALOG_LIST',
       'DBCOM_SORT', 'DBCOM_GET_SORT_MEM', 'DBCOM_SET_SORT_MEM',
       'DBCOM_GET_SORT_OPEN_BIN' and 'DBCOM_SET_SORT_OPEN_BIN'. The
       commmands 'DBCOM_REPLICATE_UPDATE', 'DBCOM_DELETE_TABLE',
       'DBCOM_CLEAR_TABLE' and 'DBCOM_COPY_TABLE' will not be processed.
       Dec/2002, Rick Smereka

       Ported to Debian Linux. Jan/2003, Rick Smereka

       Added support for the commands 'DBCOM_DELETE_FIELD',
       'DBCOM_DELETE_SUBFIELD' and 'DBCOM_DELETE_SUBSUBFIELD'. Mar/2003,
       Rick Smereka

       Modified for the updated 'socloc' API ('sloc.c').
       May/2003, Rick Smereka

       Modified for the updated 'sys_log' API ('sys_log.c').
       Modified for the updated 'bbuuzzb' API.
       Added support for the commands 'DBCOM_TRANS_NUM' and
       'DBCOM_CONNECT_NUM'. Jun/2003, Rick Smereka

       Modified default table names to use only logical table names
       for both the single user version and the client/server
       version. This will require that the database catalog be
       active (see 'dbengcfg.c') in all modes. Changed calls to
       'db_count' and 'db_get_rec_count' to use new parameters.
       Feb/2004, Rick Smereka

       Added support for the 'DBCOM_GET_AUTOPACK' and
       'DBCOM_SET_AUTOPACK' commmands. Mar/2004,
       Rick Smereka

       Added support for the commands 'DBCOM_CONFIG_CLIENT_GET_LOG' and
       'DBCOM_CONFIG_CLIENT_GET_LOG_FLAG'. The commmands
       'DBCOM_CONFIG_CLIENT_SET_LOG' and 'DBCOM_CONFIG_CLIENT_SET_LOG_FLAG'
       have not been provided for as the client log file (client/server
       only) should not be changed during the run. The application does
       not yet use the log manager ('logman') because once the log is
       turned on, the application and all the API's would start logging
       all messages. May/2004, Rick Smereka

       Added include of 'appinit.h' and added calls to register and
       de-register application name. Dec/2004, Rick Smereka

       Re-compile after changing the 'socloc' API.
       Jan/2005, Rick Smereka

       Re-compile after modifications to low level TCP socket communication
       module (ipcomm.c). Feb/2006, Rick Smereka */

    #include "stdhead.h"
    #ifndef OS_DOS
    #include "flsocket.h"
    #include "appinit.h"
    #endif
    #include "dbmess.h"
    #include "dbcomm.h"
    #include "dbiocode.h"

    #ifdef IPC_TCP
    #include "socloc.h"
    #include "sloc.h"
    #include "slconfig.h"
    #include "sliocode.h"
    #ifdef OS_WIN32
    WSADATA wsaData;
    #endif
    #endif

    #ifdef MULTIUSER
    #include "dbcs.h"
    #include "dbcscfg.h"
    #else
    #include "dbeng.h"
    #include "dblocal.h"
    #include "dbengcfg.h"
    #include "dblocfg.h"
    #endif

    #define VERSION "1.49.02-2006.02.26"
    // #define DEBUG 1
    // #define NUM_RECS 20000

    #ifdef MULTIUSER
    #define APNAME "dbstresm"
    #else
    #define APNAME "dbstress"
    #endif

    // default logical table names

    #define DS_PRIM "test.primary"
    #define DS_ALT "test.alternate"

    // default log file names that depend on platform

    #ifdef OS_UNIX
    #define DS_LOG "/work/logs/dbstres"
    #endif

    #ifdef OS_WIN32
    #define DS_LOG "C:\\LOGS\\DBSTRES"
    #endif

    #ifdef OS_DOS
    #define DS_LOG "C:\\LOGS\\DBSTRES"
    #endif

    /* function prototypes */

    int main(int, char **);
    int parse_comline(int, char **);
    int c_initialize(void);
    int check_files(void);
    int pick_com(void);
    void do_com(int);
    void c_open(void);
    void c_close(void);
    void c_next(void);
    void c_top(void);
    void c_get_rec(void);
    void c_get_field(void);
    void c_get_subfield(void);
    void c_get_subsubfield(void);
    void c_get_rec_size(void);
    void c_get_field_size(void);
    void c_get_subfield_size(void);
    void c_get_subsubfield_size(void);
    void c_goto(void);
    void c_count(void);
    void c_put_field(void);
    void c_put_subfield(void);
    void c_put_subsubfield(void);
    void c_write(void);
    void c_delete(void);
    void c_get_delete_flag(void);
    void c_set_delete_flag(void);
    void c_get_nfields(void);
    void c_get_nsubfields(void);
    void c_get_nsubsubfields(void);
    void c_get_rec_num(void);
    void c_get_pos(void);
    void c_get_change_rec_flag(void);
    void c_set_change_rec_flag(void);
    void c_pack(void);
    void c_new(void);
    void c_find(void);
    void c_find_field(void);
    void c_find_part(void);
    void c_find_field_part(void);
    void c_get_rec_count(void);
    void c_get_enf_change_rec_flag(void);
    void c_set_enf_change_rec_flag(void);
    void c_get_is_table_locked(void);
    void c_set_is_table_locked(void);
    void c_new_table(void);
    void c_config_get_tmp_path(void);
    void c_config_get_log(void);
    void c_config_get_session(void);
    void c_config_get_catalog(void);
    void c_config_get_log_flag(void);
    void c_config_get_session_flag(void);
    void c_config_get_catalog_flag(void);
    void c_config_get_replicate_flag(void);
    void c_config_get_version(void);
    void c_get_open_table_list(void);
    void c_version(void);
    void c_exist(void);
    void c_get_catalog_list(void);
    void c_sort(void);
    void c_get_sort_mem(void);
    void c_set_sort_mem(void);
    void c_get_sort_open_bin(void);
    void c_set_sort_open_bin(void);
    void c_delete_field(void);
    void c_delete_subfield(void);
    void c_delete_subsubfield(void);
    void c_trans_num(void);
    void c_connect_num(void);
    void c_get_autopack(void);
    void c_set_autopack(void);
    void c_config_client_get_log(void);
    void c_config_client_get_log_flag(void);
    void c_put_data(void);
    void term_app(void);

    #ifdef IPC_TCP
    int c_ipc_socloc_init(void);
    #endif

    /* global data */

    char *data;
    char ds_log[128], ds_prim[128], ds_alt[128];
    int tid;
    long trans_no;

    int main(int argc, char **argv)
    {
       char mes[128];
       long now;
       int dbcom;
       int ret;

       strcpy(ds_prim, DS_PRIM);
       strcpy(ds_alt, DS_ALT);

       // load log name

    #ifndef MULTIUSER
       sprintf(ds_log, "%ss.log", DS_LOG);
    #else
       sprintf(ds_log, "%sm.log", DS_LOG);
    #endif

       /* parse command line (if parameters supplied) */

       if (argc > 1)
          if (!parse_comline(argc, argv))
             return(0);

    #ifndef OS_DOS
       // register application name with 'appinit'

       if (!appinit_register_name(APNAME))
          {
          printf("%s:fatal error registering app name with appinit\n", APNAME);
          return(0);
          }
    #endif

       if (!log_start(ds_log))
          {
          printf("%s:unable to open log file, abort\n", APNAME);
          return(0);
          }

       log_console(TRUE);
       srand(time(NULL));
       // srand(time(&now) % 37);                /* seed rnd gen */
       trans_no = 1L;

       /* build logo string based on single or multi user and platform */

    #ifndef MULTIUSER
    #ifndef OS_UNIX
       /* single user non-Unix */

       log_file_date("dbstress Stand-Alone for %s Version %s", PLATFORM_STRING,
               VERSION);
    #else
       /* single user Unix */

       log_file_date("dbstress Stand-Alone for %s Version %s", SUB_PLATFORM_STRING,
               VERSION);
    #endif
    #else
    #ifndef OS_UNIX
       /* c/s non-Unix */

       log_file_date("dbstresm Client/Server for %s Version %s", PLATFORM_STRING,
               VERSION);
    #else
       /* c/s Unix */

       log_file_date("dbstresm Client/Server for %s Version %s", SUB_PLATFORM_STRING,
               VERSION);
    #endif
    #endif

       log_file_date_nf("By Rick Smereka, Copyright (c) 1997-2006");

       /* initialize local engine if we are running locally or
          startup the 'socloc' interface (TCP only) and connect to a
          Bbuuzzb database server if we are running in
          client/server mode */

       if (!c_initialize())
          {
          term_app();
          return(0);
          }

       /* initialize for system logging, used only for debugging */

    #ifdef DEBUG
    #ifndef OS_DOS
       /* if ((ret = sys_log_init(APNAME)) != SYS_LOG_OK)
          {
          sys_log_code_string(ret, mes);
          printf("%s:bad rc[%s] from sys_log_init, program abort\n",
                 APNAME, mes);
          term_app();
          return(0);
          } */

    #ifdef MULTIUSER
       if (logman_start("/work/logs/dbeng.log", APNAME))
          {
          printf("%s:unable to start log\n", APNAME);
          term_app();
          return(0);
          }
    #else
       if ((ret = db_config_set_log_flag(TRUE)) != DBENG_OK)
          {
          printf("%s:unable to start log\n", APNAME);
          term_app();
          return(0);
          }
    #endif
       logman_console(TRUE);
    #endif
    #endif

       /* get and display 'dbeng' version */

       if ((ret = db_config_get_version(mes)) != DBENG_OK)
          {
          db_io_code_string(ret, mes);
          printf("%s:error getting 'dbeng' version,rc=%s\n", APNAME, mes);
          term_app();
          return(0);
          }

       log_file_date("based on version %s of the 'Bbuuzzb' database engine", mes);
       log_file_date("%s comes with ABSOLUTELY NO WARRANTY", APNAME);
       log_file_date_nf("This is free software, and you are welcome to redistribute it");
       log_file_date_nf("under certain conditions; see 'gpl.txt' for information.");

       /* allocate storage for record data, 32000 bytes should be enough */

       if ((data = (char *)malloc(32000)) == NULL)
          {
          printf("alloc fail 'data', program abort\n");
          term_app();
          return(0);
          }

       /* check primary and alternate table names */

       if (!check_files())
          {
          free(data);
          term_app();
          return(0);
          }

       /* display primary table, alternate table and log file names */

       log_file_date("%s:primary table is %s,tid=%d", APNAME, ds_prim, tid);
       log_file_date("%s:alternate table is %s", APNAME, ds_alt);
       log_file_date("%s:log file is %s", APNAME, ds_log);

       /* main loop, infinite */

       while(1)
          {
          dbcom = pick_com();
          trans_no++;
          do_com(dbcom);
          }

       free(data);
       term_app();
       return(0);
    }

    int parse_comline(int c_count, char **c_parm)
    {
       /* Parse the command line for parameters. Function
          returns 'TRUE' if no error was detected, 'FALSE'
          otherwise. */

       int parms = 1, done = FALSE;

       while(!done)
          {
          if (c_parm[parms][0] == SWITCH_CHAR)
             {
             switch(c_parm[parms][1])
                {
                case 'l':
                case 'L':
                   if (strlen(c_parm[parms]) > 2)
                      printf("%s:extraneous input with log file switch, "
                             "ignoring\n", APNAME);

                   parms++;

                   if (parms >= c_count)
                      {
                      printf("%s:log file switch with no file name, "
                             "program abort\n", APNAME);
                      return(FALSE);
                      }

                   strcpy(ds_log, c_parm[parms]);
                   parms++;
                   break;

                case 'p':
                case 'P':
                   if (strlen(c_parm[parms]) > 2)
                      printf("%s:extraneous input with primary table switch, "
                             "ignoring\n", APNAME);

                   parms++;

                   if (parms >= c_count)
                      {
                      printf("%s:primary table switch with no file name, "
                             "program abort\n", APNAME);
                      return(FALSE);
                      }

                   strcpy(ds_prim, c_parm[parms]);
                   parms++;
                   break;

                case 'a':
                case 'A':
                   if (strlen(c_parm[parms]) > 2)
                      printf("%s:extraneous input with alternate table switch, "
                             "ignoring\n", APNAME);

                   parms++;

                   if (parms >= c_count)
                      {
                      printf("%s:alternate table switch with no file name, "
                             "program abort\n", APNAME);
                      return(FALSE);
                      }

                   strcpy(ds_alt, c_parm[parms]);
                   parms++;
                   break;

                default:
                   printf("%s:unknown switch[%s], program abort\n", APNAME,
                          c_parm[parms]);
                   return(FALSE);
                };
             }
          else
             {
             printf("%s:unknown parameter[%s], program abort\n", APNAME,
                    c_parm[parms]);
             return(FALSE);
             }

          if (parms >= c_count)
             done = TRUE;
          }

       return(TRUE);
    }

    #ifdef MULTIUSER
    int c_initialize(void)
    {
       /* Initialize socket communication, form connection to
          'socloc' server, update the config list and connect
          to a 'Bbuuzzb' server. Function returns 'TRUE' upon
          success, 'FALSE' otherwise. */

       char mname[] = "c_initialize";
       char mes[128];
       int ret;

    #ifdef IPC_TCP
       if (!c_ipc_socloc_init())
          return(FALSE);
    #endif

       /* attempt to locate a 'Bbuuzzb' server and connect to it */

       if ((ret = db_initialize()) != DBENG_OK)
          {
          db_io_code_string(ret, mes);
          log_file_date("%s:error connecting to the Bbuuzzb server,rc[%s]. "
                        "Program abort", mname, mes);
          return(FALSE);
          }

       /* display current connected server host name and
          TCP port number */

    #ifdef IPC_TCP
       (void)db_get_active(mes, &ret);
       log_file_date("%s:connected to Bbuuzzb server %s on TCP "
                     "port %d (decimal)", mname, mes, ret);
    #endif
       return(TRUE);
    }
    #endif

    #ifndef MULTIUSER
    int c_initialize(void)
    {
       /* Start the 'DBENG' local engine, read the config file
          and display the result settings. Function returns
          'TRUE' upon success, 'FALSE' otherwise. */

       char mname[] = "c_initialize";
       char *mes;
       int ret, flag;

    #ifdef DEBUG
    #ifdef IPC_TCP
       if (!c_ipc_socloc_init())
          return(FALSE);
    #endif
    #endif

       if ((mes = (char *)malloc(DBENG_PATH_LIMIT)) == (char *)NULL)
          {
          log_file_date("%s:alloc fail[mes]. Program abort", mname);
          return(FALSE);
          }

       ret = db_initialize();

       /* interpret code from init which may be
          a fatal config error */

       switch(ret)
          {
          case DBENG_OK:
             log_file_date("%s:read config file successfully", mname);
             break;

          case DBENG_CONFIG_UNABLE_TO_OPEN:
             log_file_date("%s:config file not found, loaded defaults", mname);
             break;

          default:
             db_io_code_string(ret, mes);
             log_file_date("%s:fatal config error[%s]", mname, mes);
             log_file_date("%s:terminating", mname);
             free(mes);
             return(FALSE);
             break;
          };

       (void)db_config_get_tmp_path(mes);
       log_file_date("%s:tmp path is '%s'", mname, mes);
       (void)db_config_get_log(mes);
       log_file_date("%s:log is '%s'", mname, mes);

       if ((ret = db_config_get_catalog(mes)) == DBENG_OK)
          printf("%s:catalog is '%s'\n", mname, mes);
       else
          printf("%s:catalog name not loaded\n", mname);

       (void)db_config_get_catalog_flag(&flag);

       if (flag_2_logic_string(flag, mes))
          printf("%s:catalog is %s\n", mname, mes);

       free(mes);
       return(TRUE);
    }
    #endif

    #ifdef IPC_TCP
    int c_ipc_socloc_init(void)
    {
       /* Initialize socket communication, form connection to
          'socloc' server (TCP only) and update the config list.
          Function returns 'TRUE' upon success, 'FALSE' otherwise. */

       char mname[] = "c_ipc_socloc_init";
       char *thelist, mes[128];
       int ret;

       /* startup WinSock (if Windoze) */

    #ifdef OS_WIN32
       if (WSAStartup(WINSOCK_VERSION, &wsaData))
          {
          printf("%s:unable to start WinSock. "
                "Program abort\n", mname);
          return(FALSE);
          }
    #endif

       /* attempt to connect to a 'socloc' server */

       if ((ret = sloc_initialize()) != SL_OK)
          {
          sl_code_string(ret, mes);
          printf("%s:error initializing socloc interface,rc[%s]. "
                "Program abort\n", mname, mes);
          return(FALSE);
          }

       /* get config list from 'socloc' server and update
          the client list with it */

       if ((thelist = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
          {
          printf("%s:alloc fail[thelist]. Program abort\n", mname);
          return(FALSE);
          }

       if ((ret = sloc_config_get_list(thelist)) != SL_OK)
          {
          free(thelist);
          sl_code_string(ret, mes);
          printf("%s:error getting socloc config list,rc[%s]. "
                 "Program abort\n", mname, mes);
          return(FALSE);
          }

       if ((ret = sl_config_put_list(thelist)) != SL_OK)
          {
          sl_code_string(ret, mes);
          printf("%s:error putting socloc config list,rc[%s]. ",
                 "Program abort\n", mname, mes);
          free(thelist);
          return(FALSE);
          }

       return(TRUE);
    }
    #endif

    int check_files(void)
    {
       /* Check the resolved primary table and alternate table.
          Function returns 'TRUE' if files are valid, 'FALSE'
          otherwise. */

       char mes[128];
       int a_tid;
       int rc;

       /* open primary test table (this will stay open)
          as long as their is no error */

       if ((rc = db_open(ds_prim, &tid)) != DBENG_OK)
          {
          db_io_code_string(rc, mes);
          log_file_date("%s:primary table[%s] open failed(rc[%d]=%s), abort",
                        APNAME, ds_prim, rc, mes);
          return(FALSE);
          }

       /* check alternate table */

       if ((rc = db_open(ds_alt, &a_tid)) != DBENG_OK)
          {
          db_io_code_string(rc, mes);
          log_file_date("%s:alternate table[%s] open failed(rc[%d]=%s), abort",
                        APNAME, ds_alt, rc, mes);
          (void)db_close(tid);
          return(FALSE);
          }

       (void)db_close(a_tid);
       return(TRUE);
    }

    int pick_com(void)
    {
       /* Get a random command number in range. */

       long rec_num, pos, active_rec_count, deleted_rec_count;
       int rnd_num;
       int final;

       if ((trans_no % 500L) == 0L)
          srand(time(NULL));

       final = rnd(1, DBCOM_MAXCOM);
       (void)db_get_rec_num(tid, &rec_num);
       (void)db_get_pos(tid, &pos);
       (void)db_get_rec_count(tid, &active_rec_count, &deleted_rec_count);
       log_file_date("pick_com:c=%d,arc=%ld,drc=%ld,rn=%ld,pos=%ld,t=%ld",
                     final, active_rec_count, deleted_rec_count, rec_num,
                     pos, trans_no);
       return(final);
    }

    void do_com(int com_num)
    {
       /* Dispatch command. */

       switch(com_num)
          {
          case DBCOM_OPEN:
             c_open();
             break;

          case DBCOM_CLOSE:
             c_close();
             break;

          case DBCOM_NEXT:
             c_next();
             break;

          case DBCOM_TOP:
             c_top();
             break;

          case DBCOM_GET_REC:
             c_get_rec();
             break;

          case DBCOM_GET_FIELD:
             c_get_field();
             break;

          case DBCOM_GOTO:
             c_goto();
             break;

          case DBCOM_COUNT:
             c_count();
             break;

          case DBCOM_PUT_FIELD:
             c_put_field();
             break;

          case DBCOM_WRITE:
             c_write();
             break;

          case DBCOM_DELETE:
             c_delete();
             break;

          case DBCOM_GET_DELETE_FLAG:
             c_get_delete_flag();
             break;

          case DBCOM_SET_DELETE_FLAG:
             c_set_delete_flag();
             break;

          case DBCOM_GET_NFIELDS:
             c_get_nfields();
             break;

          case DBCOM_GET_REC_SIZE:
             c_get_rec_size();
             break;

          case DBCOM_GET_FIELD_SIZE:
             c_get_field_size();
             break;

          case DBCOM_GET_REC_NUM:
             c_get_rec_num();
             break;

          case DBCOM_GET_POS:
             c_get_pos();
             break;

          case DBCOM_GET_CHANGE_REC_FLAG:
             c_get_change_rec_flag();
             break;

          case DBCOM_SET_CHANGE_REC_FLAG:
             c_set_change_rec_flag();
             break;

          case DBCOM_PACK:
             c_pack();
             break;

          case DBCOM_NEW:
             c_new();
             break;

          case DBCOM_FIND:
             c_find();
             break;

          case DBCOM_FIND_FIELD:
             c_find_field();
             break;

          case DBCOM_FIND_PART:
             c_find_part();
             break;

          case DBCOM_FIND_FIELD_PART:
             c_find_field_part();
             break;

          case DBCOM_GET_REC_COUNT:
             c_get_rec_count();
             break;

          case DBCOM_GET_ENF_CHANGE_REC_FLAG:
             c_get_enf_change_rec_flag();
             break;

          case DBCOM_SET_ENF_CHANGE_REC_FLAG:
             c_set_enf_change_rec_flag();
             break;

          case DBCOM_GET_IS_TABLE_LOCKED:
             c_get_is_table_locked();
             break;

          case DBCOM_SET_IS_TABLE_LOCKED:
             c_set_is_table_locked();
             break;

          case DBCOM_NEW_TABLE:
             c_new_table();
             break;

          case DBCOM_CONFIG_GET_TMP_PATH:
             c_config_get_tmp_path();
             break;

          case DBCOM_CONFIG_GET_LOG:
             c_config_get_log();
             break;

          case DBCOM_CONFIG_GET_SESSION:
             c_config_get_session();
             break;

          case DBCOM_CONFIG_GET_CATALOG:
             c_config_get_catalog();
             break;

          case DBCOM_CONFIG_GET_LOG_FLAG:
             c_config_get_log_flag();
             break;

          case DBCOM_CONFIG_GET_SESSION_FLAG:
             c_config_get_session_flag();
             break;

          case DBCOM_CONFIG_GET_CATALOG_FLAG:
             c_config_get_catalog_flag();
             break;

          case DBCOM_CONFIG_GET_REPLICATE_FLAG:
             c_config_get_replicate_flag();
             break;

          case DBCOM_CONFIG_GET_VERSION:
             c_config_get_version();
             break;

          case DBCOM_GET_OPEN_TABLE_LIST:
             c_get_open_table_list();
             break;

          case DBCOM_GET_NSUBFIELDS:
             c_get_nsubfields();
             break;

          case DBCOM_GET_NSUBSUBFIELDS:
             c_get_nsubsubfields();
             break;

          case DBCOM_GET_SUBFIELD_SIZE:
             c_get_subfield_size();
             break;

          case DBCOM_GET_SUBSUBFIELD_SIZE:
             c_get_subsubfield_size();
             break;

          case DBCOM_GET_SUBFIELD:
             c_get_subfield();
             break;

          case DBCOM_GET_SUBSUBFIELD:
             c_get_subsubfield();
             break;

          case DBCOM_PUT_SUBFIELD:
             c_put_subfield();
             break;

          case DBCOM_PUT_SUBSUBFIELD:
             c_put_subsubfield();
             break;

          case DBCOM_VERSION:
             c_version();
             break;

          case DBCOM_EXIST:
             c_exist();
             break;

          case DBCOM_GET_CATALOG_LIST:
             c_get_catalog_list();
             break;

          case DBCOM_SORT:
             c_sort();
             break;

          case DBCOM_GET_SORT_MEM:
             c_get_sort_mem();
             break;

          case DBCOM_SET_SORT_MEM:
             c_set_sort_mem();
             break;

          case DBCOM_GET_SORT_OPEN_BIN:
             c_get_sort_open_bin();
             break;

          case DBCOM_SET_SORT_OPEN_BIN:
             c_set_sort_open_bin();
             break;

          case DBCOM_DELETE_FIELD:
             c_delete_field();
             break;

          case DBCOM_DELETE_SUBFIELD:
             c_delete_subfield();
             break;

          case DBCOM_DELETE_SUBSUBFIELD:
             c_delete_subsubfield();
             break;

          case DBCOM_TRANS_NUM:
             c_trans_num();
             break;

          case DBCOM_CONNECT_NUM:
             c_connect_num();
             break;

          case DBCOM_GET_AUTOPACK:
             c_get_autopack();
             break;

          case DBCOM_SET_AUTOPACK:
             c_set_autopack();
             break;

          case DBCOM_CONFIG_CLIENT_GET_LOG:
             c_config_client_get_log();
             break;

          case DBCOM_CONFIG_CLIENT_GET_LOG_FLAG:
             c_config_client_get_log_flag();
             break;

          default:
             log_file_date("do_com:unknown com[%d], ignoring", com_num);
          };
    }

    void c_open(void)
    {
       /* Test 'open' function by opening and then closing a secondary table. */

       char mes[50];
       int ret;
       int atid;

       ret = db_open(ds_alt, &atid);
       db_io_code_string(ret, mes);
       log_file_date("c_open:open,rc=%s", mes);
       ret = db_close(atid);
       db_io_code_string(ret, mes);
       log_file_date("c_open:close,t=%d,rc=%s", atid, mes);
    }

    void c_close(void)
    {
       /* Test 'close' function by opening and then closing a secondary table. */

       char mes[50];
       int ret;
       int atid;

       ret = db_open(ds_alt, &atid);
       db_io_code_string(ret, mes);
       log_file_date("c_close:open,rc=%s", mes);
       ret = db_close(atid);
       db_io_code_string(ret, mes);
       log_file_date("c_close:close,t=%d,rc=%s", atid, mes);
    }

    void c_next(void)
    {
       /* Test 'next' function by going to next record. If 'eof' is
          detected, go to the top of the table and get first record. */

       char mes[50];
       int ret;

       ret = db_next(tid);

       if (ret == DBENG_EOF)
          {
          log_file_date_nf("c_next:eof detected, getting first");
          (void)db_top(tid);
          ret = db_next(tid);
          }

       db_io_code_string(ret, mes);
       log_file_date("c_next:rc=%s", mes);
    }

    void c_top(void)
    {
       /* Test 'top' function by going to top of the table and getting the
          first record. */

       char mes[50];
       int ret;

       ret = db_top(tid);

       if (ret != DBENG_OK)
          {
          db_io_code_string(ret, mes);
          log_file_date("c_top:bad rc=%s", mes);
          return;
          }

       ret = db_next(tid);
       db_io_code_string(ret, mes);
       log_file_date("c_top:rc=%s", mes);
    }

    void c_get_rec(void)
    {
       /* Test 'get_rec' function by getting the contents of the current
          record. */

       char mes[50];
       int ret;

       ret = db_get_rec(tid, data);
       db_io_code_string(ret, mes);
       log_file_date("c_get_rec:l=%d,rc=%s", strlen(data), mes);
    }

    void c_get_field(void)
    {
       /* Test 'get_field' function by getting the contents of a
          randomly selected field. */

       char mes[50];
       int ret;
       int nfields;
       int which;

       ret = db_get_nfields(tid, &nfields);

       if (ret != DBENG_OK)
          {
          db_io_code_string(ret, mes);
          log_file_date("c_get_field:nfields,rc=%s", mes);
          return;
          }

       which = (nfields > 1) ? rnd(1, nfields) : 1;
       ret = db_get_field(tid, which, data);
       db_io_code_string(ret, mes);
       log_file_date("c_get_field:f=%d,d=%s,l=%d,rc=%s", which, data,
                     strlen(data), mes);
    }

    void c_get_subfield(void)
    {
       /* Test 'get.subfield' function. */

       char mes[50];
       int ret;
       int nfields, nsubfields;
       int which_field, which_subfield;

       ret = db_get_nfields(tid, &nfields);

       if (ret != DBENG_OK)
          {
          db_io_code_string(ret, mes);
          log_file_date("c_get_subfield:nfields,rc=%s", mes);
          return;
          }

       which_field = (nfields > 1) ? rnd(1, nfields) : 1;
       ret = db_get_nsubfields(tid, which_field, &nsubfields);

       if (ret != DBENG_OK)
          {
          db_io_code_string(ret, mes);
          log_file_date("c_get_subfield:nsubfields,rc=%s", mes);
          return;
          }

       which_subfield = (nsubfields > 1) ? rnd(1, nsubfields) : 1;
       ret = db_get_subfield(tid, which_field, which_subfield, data);
       db_io_code_string(ret, mes);
       log_file_date("c_get_subfield:f=%d,sf=%d,d=%s,l=%d,rc=%s", which_field,
                     which_subfield, data, strlen(data), mes);
    }

    void c_get_subsubfield(void)
    {
       /* Test 'get.subsubfield' function. */

       char mes[50];
       int ret;
       int nfields, nsubfields, nsubsubfields;
       int which_field, which_subfield, which_subsubfield;

       ret = db_get_nfields(tid, &nfields);

       if (ret != DBENG_OK)
          {
          db_io_code_string(ret, mes);
          log_file_date("c_get_subsubfield:nfields,rc=%s", mes);
          return;
          }

       which_field = (nfields > 1) ? rnd(1, nfields) : 1;
       ret = db_get_nsubfields(tid, which_field, &nsubfields);

       if (ret != DBENG_OK)
          {
          db_io_code_string(ret, mes);
          log_file_date("c_get_subsubfield:nsubfields,rc=%s", mes);
          return;
          }

       which_subfield = (nsubfields > 1) ? rnd(1, nsubfields) : 1;
       ret = db_get_nsubsubfields(tid, which_field, which_subfield,
                                  &nsubsubfields);

       if (ret != DBENG_OK)
          {
          db_io_code_string(ret, mes);
          log_file_date("c_get_subsubfield:nsubsubfields,rc=%s", mes);
          return;
          }

       which_subsubfield = (nsubsubfields > 1) ? rnd(1, nsubsubfields) : 1;
       ret = db_get_subsubfield(tid, which_field, which_subfield,
                                which_subsubfield, data);
       db_io_code_string(ret, mes);
       log_file_date("c_get_subsubfield:f=%d,sf=%d,ssf=%d,d=%s,l=%d,rc=%s",
                     which_field, which_subfield, which_subsubfield,
                     data, strlen(data), mes);
    }

    void c_get_rec_size(void)
    {
       /* Test 'get_rec_size' function by getting the size of the
          current record. */

       char mes[50];
       int ret;
       int rsize;

       ret = db_get_rec_size(tid, &rsize);
       db_io_code_string(ret, mes);
       log_file_date("c_get_rec_size:s=%d,rc=%s", rsize, mes);
    }

    void c_get_field_size(void)
    {
       /* Test 'get_field_size' function by getting the size of a
          a randomly selected field. */

       char mes[50];
       int ret;
       int nfields;
       int which;
       int fsize;

       ret = db_get_nfields(tid, &nfields);

       if (ret != DBENG_OK)
          {
          db_io_code_string(ret, mes);
          log_file_date("c_get_field:nfields,rc=%s", mes);
          return;
          }

       which = (nfields > 1) ? rnd(1, nfields) : 1;
       ret = db_get_field_size(tid, which, &fsize);
       db_io_code_string(ret, mes);
       log_file_date("c_get_field_size:f=%d,l=%d,rc=%s", which, fsize, mes);
    }

    void c_get_subfield_size(void)
    {
       /* Test 'get.subfield.size' function. */

       char mes[50];
       int ret;
       int nfields, nsubfields, size;
       int which_field, which_subfield;

       ret = db_get_nfields(tid, &nfields);

       if (ret != DBENG_OK)
          {
          db_io_code_string(ret, mes);
          log_file_date("c_get_subfield_size:nfields,rc=%s", mes);
          return;
          }

       which_field = (nfields > 1) ? rnd(1, nfields) : 1;
       ret = db_get_nsubfields(tid, which_field, &nsubfields);

       if (ret != DBENG_OK)
          {
          db_io_code_string(ret, mes);
          log_file_date("c_get_subfield_size:nsubfields,rc=%s", mes);
          return;
          }

       which_subfield = (nsubfields > 1) ? rnd(1, nsubfields) : 1;
       ret = db_get_subfield_size(tid, which_field, which_subfield, &size);
       db_io_code_string(ret, mes);
       log_file_date("c_get_subfield_size:f=%d,sf=%d,size=%d,rc=%s", which_field,
                     which_subfield, size, mes);
    }

    void c_get_subsubfield_size(void)
    {
       /* Test 'get.subsubfield.size' function. */

       char mes[50];
       int ret;
       int nfields, nsubfields, nsubsubfields, size;
       int which_field, which_subfield, which_subsubfield;

       ret = db_get_nfields(tid, &nfields);

       if (ret != DBENG_OK)
          {
          db_io_code_string(ret, mes);
          log_file_date("c_get_subsubfield_size:nfields,rc=%s", mes);
          return;
          }

       which_field = (nfields > 1) ? rnd(1, nfields) : 1;
       ret = db_get_nsubfields(tid, which_field, &nsubfields);

       if (ret != DBENG_OK)
          {
          db_io_code_string(ret, mes);
          log_file_date("c_get_subsubfield_size:nsubfields,rc=%s", mes);
          return;
          }

       which_subfield = (nsubfields > 1) ? rnd(1, nsubfields) : 1;
       ret = db_get_nsubsubfields(tid, which_field, which_subfield, &nsubsubfields);

       if (ret != DBENG_OK)
          {
          db_io_code_string(ret, mes);
          log_file_date("c_get_subsubfield_size:nsubsubfields,rc=%s", mes);
          return;
          }

       which_subsubfield = (nsubsubfields > 1) ? rnd(1, nsubsubfields) : 1;
       ret = db_get_subsubfield_size(tid, which_field, which_subfield,
                                     which_subsubfield, &size);
       db_io_code_string(ret, mes);
       log_file_date("c_get_subsubfield_size:f=%d,sf=%d,ssf=%d,size=%d,rc=%s",
                     which_field, which_subfield, which_subsubfield, size, mes);
    }

    void c_goto(void)
    {
       /* Test 'goto' function by going to a randomly selected record. */

       char mes[50];
       long active_rec_count, deleted_rec_count;
       int ret;
       long which;

       /* pick a random number zero to rec count + 10 */

       (void)db_get_rec_count(tid, &active_rec_count, &deleted_rec_count);
       which = (long)rnd(0, (int)active_rec_count + 10);
       ret = db_goto(tid, which);
       db_io_code_string(ret, mes);
       log_file_date("c_goto:r=%ld,rc=%s", which, mes);
    }

    void c_count(void)
    {
       /* Test 'count' function. */

       char mes[50];
       long active_rec_count, deleted_rec_count;
       int ret;

       ret = db_count(tid, &active_rec_count, &deleted_rec_count);
       db_io_code_string(ret, mes);
       log_file_date("c_count:ac=%ld,dc=%ld,rc=%s", active_rec_count,
                     deleted_rec_count, mes);
    }

    void c_put_field(void)
    {
       /* Test 'put_field' function by writing a random field with
          a random number of digits. */

       char mes[50];
       int ret;
       int fnum;

       /* pick a random number between 0 and 254 for field number */

       fnum = rnd(0, 254);

       /* build field */

       c_put_data();
       ret = db_put_field(tid, fnum, data);
       db_io_code_string(ret, mes);
       log_file_date("c_put_field:f=%d,d=%s,l=%d,rc=%s", fnum, data,
                     strlen(data), mes);
    }

    void c_put_subfield(void)
    {
       /* Test 'put.subfield' function. */

       char mes[50];
       int ret;
       int fnum, sfnum;

       /* pick a random number between 0 and 254 for field number and
          0 to 9 for subfield number */

       fnum = rnd(0, 254);
       sfnum = rnd(0, 9);

       /* build subfield */

       c_put_data();
       ret = db_put_subfield(tid, fnum, sfnum, data);
       db_io_code_string(ret, mes);
       log_file_date("c_put_subfield:f=%d,sf=%d,d=%s,l=%d,rc=%s", fnum, sfnum,
                     data, strlen(data), mes);
    }

    void c_put_subsubfield(void)
    {
       /* Test 'put.subsubfield' function. */

       char mes[50];
       int ret;
       int fnum, sfnum, ssfnum;

       /* pick a random number between 0 and 254 for field number,
          0 to 9 for subfield number and subsubfield number */

       fnum = rnd(0, 254);
       sfnum = rnd(0, 9);
       ssfnum = rnd(0, 9);

       /* build subsubfield */

       c_put_data();
       ret = db_put_subsubfield(tid, fnum, sfnum, ssfnum, data);
       db_io_code_string(ret, mes);
       log_file_date("c_put_subsubfield:f=%d,sf=%d,ssf=%d,d=%s,l=%d,rc=%s",
                     fnum, sfnum, ssfnum, data, strlen(data), mes);
    }

    void c_write(void)
    {
       /* Test 'write' function. */

       char mes[50];
       int ret;

       ret = db_write(tid);
       db_io_code_string(ret, mes);
       log_file_date("c_write:rc=%s", mes);
    }

    void c_delete(void)
    {
       /* Test 'delete' function. */

       char mes[50];
       int ret;

       ret = db_delete(tid);
       db_io_code_string(ret, mes);
       log_file_date("c_delete:rc=%s", mes);
    }

    void c_get_delete_flag(void)
    {
       /* Test 'get_del_flag' function. */

       char mes[50];
       int ret;
       int del_flag;

       ret = db_get_delete_flag(tid, &del_flag);
       db_io_code_string(ret, mes);
       log_file_date("c_get_del_flag:f=%d,rc=%s", del_flag, mes);
    }

    void c_set_delete_flag(void)
    {
       /* Test 'set_del_flag' function. */

       char mes[50];
       int ret;
       int del_flag;

       del_flag = rnd(0, 2);         /* generate illegal values on purpose */
       ret = db_set_delete_flag(tid, del_flag);
       db_io_code_string(ret, mes);
       log_file_date("c_set_delete_flag:f=%d,rc=%s", del_flag, mes);
    }

    void c_get_nfields(void)
    {
       /* Test 'get_nfields' function. */

       char mes[50];
       int ret;
       int nfields;

       ret = db_get_nfields(tid, &nfields);
       db_io_code_string(ret, mes);
       log_file_date("c_nfields:f=%d,rc=%s", nfields, mes);
    }

    void c_get_nsubfields(void)
    {
       /* Test 'get.nsubfields' function. */

       char mes[50];
       int ret;
       int nfields, nsubfields;
       int which;

       ret = db_get_nfields(tid, &nfields);

       if (ret != DBENG_OK)
          {
          db_io_code_string(ret, mes);
          log_file_date("c_get_nsubfields:nfields,rc=%s", mes);
          return;
          }

       which = (nfields > 1) ? rnd(1, nfields) : 1;
       ret = db_get_nsubfields(tid, which, &nsubfields);
       db_io_code_string(ret, mes);
       log_file_date("c_get_nsubfields:f=%d,nsubfields=%d,rc=%s", which,
                     nsubfields, mes);
    }

    void c_get_nsubsubfields(void)
    {
       /* Test 'get.nsubsubfields' function. */

       char mes[50];
       int ret;
       int nfields, nsubfields, nsubsubfields;
       int which_field, which_subfield;

       ret = db_get_nfields(tid, &nfields);

       if (ret != DBENG_OK)
          {
          db_io_code_string(ret, mes);
          log_file_date("c_get_nsubsubfields:nfields,rc=%s", mes);
          return;
          }

       which_field = (nfields > 1) ? rnd(1, nfields) : 1;
       ret = db_get_nsubfields(tid, which_field, &nsubfields);

       if (ret != DBENG_OK)
          {
          db_io_code_string(ret, mes);
          log_file_date("c_get_nsubsubfields:nsubfields,rc=%s", mes);
          return;
          }

       which_subfield = (nsubfields > 1) ? rnd(1, nsubfields) : 1;
       ret = db_get_nsubsubfields(tid, which_field, which_subfield,
                                  &nsubsubfields);
       db_io_code_string(ret, mes);
       log_file_date("c_get_nsubsubfields:f=%d,sf=%d,nsubsubfields=%d,rc=%s",
                     which_field, which_subfield, nsubsubfields, mes);
    }

    void c_get_rec_num(void)
    {
       /* Test 'get_rec_num' function. */

       char mes[50];
       int ret;
       long rec_num;

       ret = db_get_rec_num(tid, &rec_num);
       db_io_code_string(ret, mes);
       log_file_date("c_get_rec_num:r=%ld,rc=%s", rec_num, mes);
    }

    void c_get_pos(void)
    {
       /* Test 'get_pos' function. */

       char mes[50];
       int ret;
       long pos;

       ret = db_get_pos(tid, &pos);
       db_io_code_string(ret, mes);
       log_file_date("c_get_pos:p=%ld,rc=%s", pos, mes);
    }

    void c_get_change_rec_flag(void)
    {
       /* Test 'get_change_rec_flag' function. */

       char mes[50];
       int ret;
       int flag;

       ret = db_get_change_rec_flag(tid, &flag);
       db_io_code_string(ret, mes);
       log_file_date("c_get_change_rec_flag:f=%d,rc=%s", flag, mes);
    }

    void c_set_change_rec_flag(void)
    {
       /* Test 'set_change_rec_flag' function. */

       char mes[50];
       int ret;
       int rec_flag;

       rec_flag = rnd(0, 2);         /* generate illegal values on purpose */
       ret = db_set_change_rec_flag(tid, rec_flag);
       db_io_code_string(ret, mes);
       log_file_date("c_set_change_rec_flag:f=%d,rc=%s", rec_flag, mes);
    }

    void c_pack(void)
    {
       /* Test 'pack' function. */

       char mes[50];
       int ret;

       ret = db_pack(tid);
       db_io_code_string(ret, mes);
       log_file_date("c_pack:rc=%s", mes);
    }

    void c_new(void)
    {
       /* Test 'new' function. */

       char mes[50];
       int ret;

       ret = db_new(tid);
       db_io_code_string(ret, mes);
       log_file_date("c_new:rc=%s", mes);
    }

    void c_find(void)
    {
       /* Test 'find' function by creating a random field and
          searching for it. */

       char mes[50];
       char fdata_char[25];
       int ret;
       int fdata;
       int fnum;
       int cs_flag;

       /* pick a random number between 0 and 399 for field data, we
          intentionally have the maximum range too large */

       fdata = rnd(0, 399);

       /* decide whether to use case sensitivity, can also generate
          illegal values (0-2) */

       cs_flag = rnd(0, 2);
       sprintf(fdata_char, "%d", fdata);
       ret = db_find(tid, cs_flag, fdata_char, &fnum);
       db_io_code_string(ret, mes);
       log_file_date("c_find:cs=%d,fd=%s,fn=%d,rc=%s", cs_flag, fdata_char,
                     fnum, mes);
    }

    void c_find_field(void)
    {
       /* Test 'find_field' function by creating a random field and
          searching for it. */

       char mes[50];
       char fdata_char[25];
       int ret;
       int fdata;
       int fnum;
       int cs_flag;

       /* pick a random number between 0 and 399 for field data, we
          intentionally have the maximum range too large and a possible
          zero value */

       fdata = rnd(0, 399);

       /* decide whether to use case sensitivity, can also generate
          illegal values (0-2) */

       cs_flag = rnd(0, 2);

       /* decide on which field to search, can also generate illegal values */

       fnum = rnd(0, 19);

       sprintf(fdata_char, "%d", fdata);
       ret = db_find_field(tid, cs_flag, fdata_char, fnum);
       db_io_code_string(ret, mes);
       log_file_date("c_find_field:cs=%d,fd=%s,fn=%d,rc=%s", cs_flag,
                     fdata_char, fnum, mes);
    }

    void c_find_part(void)
    {
       /* Test 'find_part' function by creating a random field and
          searching for it. */

       char mes[50];
       char fdata_char[25];
       int ret;
       int fdata;
       int fnum;
       int cs_flag;

       /* pick a random number between 0 and 399 for field data, we
          intentionally have the maximum range too large */

       fdata = rnd(0, 399);

       /* decide whether to use case sensitivity, can also generate
          illegal values (0-2) */

       cs_flag = rnd(0, 2);
       sprintf(fdata_char, "%d", fdata);
       ret = db_find_part(tid, cs_flag, fdata_char, &fnum);
       db_io_code_string(ret, mes);
       log_file_date("c_find_part:cs=%d,fd=%s,fn=%d,rc=%s", cs_flag,
                     fdata_char, fnum, mes);
    }

    void c_find_field_part(void)
    {
       /* Test 'find_field_part' function by creating a random field and
          searching for it. */

       char mes[50];
       char fdata_char[25];
       int ret;
       int fdata;
       int fnum;
       int cs_flag;

       /* pick a random number between 0 and 399 for field data, we
          intentionally have the maximum range too large and a possible
          zero value */

       fdata = rnd(0, 399);

       /* decide whether to use case sensitivity, can also generate
          illegal values (0-2) */

       cs_flag = rnd(0, 2);

       /* decide on which field to search, can also generate illegal values */

       fnum = rnd(0, 20);

       sprintf(fdata_char, "%d", fdata);
       ret = db_find_field_part(tid, cs_flag, fdata_char, fnum);
       db_io_code_string(ret, mes);
       log_file_date("c_find_field_part:cs=%d,fd=%s,fn=%d,rc=%s",
                     cs_flag, fdata_char, fnum, mes);
    }

    void c_get_rec_count(void)
    {
       /* Test 'get_record_count' function. */

       char mes[50];
       long active_rec_count, deleted_rec_count;
       int ret;

       ret = db_get_rec_count(tid, &active_rec_count, &deleted_rec_count);
       db_io_code_string(ret, mes);
       log_file_date("c_get_record_count:ac=%ld,dc=%ld,rc=%s", active_rec_count,
                     deleted_rec_count, mes);
    }

    void c_get_enf_change_rec_flag(void)
    {
       /* Test 'get_enf_change_rec_flag' function. */

       char mes[50];
       int ret;
       int flag;

       ret = db_get_enf_change_rec_flag(tid, &flag);
       db_io_code_string(ret, mes);
       log_file_date("c_get_enf_change_rec_flag:f=%d,rc=%s", flag, mes);
    }

    void c_set_enf_change_rec_flag(void)
    {
       /* Test 'set_enf_change_rec_flag' function. */

       char mes[50];
       int ret;
       int rec_flag;

       rec_flag = rnd(0, 2);         /* generate illegal values on purpose */
       ret = db_set_enf_change_rec_flag(tid, rec_flag);
       db_io_code_string(ret, mes);
       log_file_date("c_set_enf_change_rec_flag:f=%d,rc=%s", rec_flag, mes);
    }

    void c_get_is_table_locked(void)
    {
       /* Test 'get_is_table_locked' function. */

       char mes[50];
       int ret;
       int flag;

       ret = db_get_is_table_locked(tid, &flag);
       db_io_code_string(ret, mes);
       log_file_date("c_get_is_table_locked:f=%d,rc=%s", flag, mes);
    }

    void c_set_is_table_locked(void)
    {
       /* Test 'set_is_table_locked' function. */

       char mes[50];
       int ret;
       int rec_flag;

       rec_flag = rnd(0, 2);         /* generate illegal values on purpose */
       ret = db_set_is_table_locked(tid, rec_flag);
       db_io_code_string(ret, mes);
       log_file_date("c_set_is_table_locked:f=%d,rc=%s", rec_flag, mes);
    }

    void c_new_table(void)
    {
       /* Test 'new_table' function. Available in single user mode
          only. */

    #ifdef MULTIUSER
       log_file_date("c_new_table:command not implemented in c/s mode");
       return;
    #else
       char *tmp_path, *dest_table_name;
       char rname[13], mes[50];
       int tid, tid_flag, ret;

       /* get temporary path from config data */

       if ((tmp_path = (char *)malloc(DBENG_PATH_LIMIT)) == (char *)NULL)
          {
          db_io_code_string(DBENG_MEMORY_FAIL, mes);
          log_file_date("c_new_table:alloc fail 'tmp_path',rc=%s", mes);
          return;
          }

       if ((ret = db_config_get_tmp_path(tmp_path)) != DBENG_OK)
          {
          db_io_code_string(ret, mes);
          log_file_date("c_new_table:error getting config tmp path,rc=%s", mes);
          free(tmp_path);
          return;
          }

       /* generate a unique file name */

       if (!unique(tmp_path, rname))
          {
          db_io_code_string(DBENG_CANNOT_CREATE_TABLE, mes);
          log_file_date("c_new_table:error generating unique file name,rc=%s", mes);
          free(tmp_path);
          return;
          }

       if ((dest_table_name = malloc(1024)) == NULL)
          {
          db_io_code_string(DBENG_MEMORY_FAIL, mes);
          log_file_date("c_new_table:alloc fail 'dest_table_name',rc=%s", mes);
          free(tmp_path);
          return;
          }

       /* build complete path and file name */

       sprintf(dest_table_name, "%s%c%s", tmp_path, PATH_SEP, rname);
       free(tmp_path);
       tid_flag = rnd(0, 2);
       tid = tid_flag;
       ret = db_new_table(dest_table_name, &tid);
       db_io_code_string(ret, mes);
       log_file_date("c_new_table:dtn=%s,tf=%d,tid=%d,rc=%s", dest_table_name,
                     tid_flag, tid, mes);

       if (tid_flag)
          {
          ret = db_close(tid);

          if (ret != DBENG_OK)
             {
             db_io_code_string(ret, mes);
             log_file_date("c_new_table:close failed,rc=%s", mes);
             }
          }

       unlink(dest_table_name);
       free(dest_table_name);
    #endif
    }

    void c_config_get_tmp_path(void)
    {
       /* Test the 'config_get_tmp_path' function. */

       char *tmp_path, mes[50];
       int ret;

       if ((tmp_path = (char *)malloc(DBENG_PATH_LIMIT)) == (char *)NULL)
          {
          db_io_code_string(DBENG_MEMORY_FAIL, mes);
          log_file_date("c_config_get_tmp_path:alloc fail 'tmp_path',rc=%s", mes);
          return;
          }

       if ((ret = db_config_get_tmp_path(tmp_path)) != DBENG_OK)
          {
          db_io_code_string(ret, mes);
          log_file_date("c_config_get_tmp_path:error getting config tmp path,rc=%s", mes);
          free(tmp_path);
          return;
          }

       db_io_code_string(ret, mes);
       log_file_date("c_config_get_tmp_path:path=%s,rc=%s", tmp_path, mes);
       free(tmp_path);
    }

    void c_config_get_log(void)
    {
       /* Test the 'config_get_log' function. */

       char *slog, mes[50];
       int ret;

       if ((slog = (char *)malloc(DBENG_PATH_LIMIT)) == (char *)NULL)
          {
          db_io_code_string(DBENG_MEMORY_FAIL, mes);
          log_file_date("c_config_get_log:alloc fail 'slog',rc=%s", mes);
          return;
          }

       if ((ret = db_config_get_log(slog)) != DBENG_OK)
          {
          db_io_code_string(ret, mes);
          log_file_date("c_config_get_log:error getting config log,rc=%s", mes);
          free(slog);
          return;
          }

       db_io_code_string(ret, mes);
       log_file_date("c_config_get_log:log=%s,rc=%s", slog, mes);
       free(slog);
    }

    void c_config_get_session(void)
    {
       /* Test the 'config_get_session' function. */

       char *sessiont, mes[50];
       int ret;

       if ((sessiont = (char *)malloc(DBENG_PATH_LIMIT)) == (char *)NULL)
          {
          db_io_code_string(DBENG_MEMORY_FAIL, mes);
          log_file_date("c_config_get_session:alloc fail 'sessiont',rc=%s", mes);
          return;
          }

       if ((ret = db_config_get_session(sessiont)) != DBENG_OK)
          {
          db_io_code_string(ret, mes);
          log_file_date("c_config_get_session:error getting config session table,"
                        "rc=%s", mes);
          free(sessiont);
          return;
          }

       db_io_code_string(ret, mes);
       log_file_date("c_config_get_session:session table=%s,rc=%s", sessiont, mes);
       free(sessiont);
    }

    void c_config_get_catalog(void)
    {
       /* Test the 'config_get_catalog' function. */

       char *catalogt, mes[50];
       int ret;

       if ((catalogt = (char *)malloc(DBENG_PATH_LIMIT)) == (char *)NULL)
          {
          db_io_code_string(DBENG_MEMORY_FAIL, mes);
          log_file_date("c_config_get_catalog:alloc fail 'catalogt',rc=%s", mes);
          return;
          }

       if ((ret = db_config_get_catalog(catalogt)) != DBENG_OK)
          {
          db_io_code_string(ret, mes);
          log_file_date("c_config_get_catalog:error getting config catalog table,"
                        "rc=%s", mes);
          free(catalogt);
          return;
          }

       db_io_code_string(ret, mes);
       log_file_date("c_config_get_catalog:catalog table=%s,rc=%s", catalogt, mes);
       free(catalogt);
    }

    void c_config_get_log_flag(void)
    {
       /* Test the 'config_get_log_flag' function. */

       char mes[50];
       int ret;
       int flag;

       ret = db_config_get_log_flag(&flag);
       db_io_code_string(ret, mes);
       log_file_date("c_config_get_log_flag:f=%d,rc=%s", flag, mes);
    }

    void c_config_get_session_flag(void)
    {
       /* Test the 'config_get_session_flag' function. */

       char mes[50];
       int ret;
       int flag;

       ret = db_config_get_session_flag(&flag);
       db_io_code_string(ret, mes);
       log_file_date("c_config_get_session_flag:f=%d,rc=%s", flag, mes);
    }

    void c_config_get_catalog_flag(void)
    {
       /* Test the 'config_get_catalog_flag' function. */

       char mes[50];
       int ret;
       int flag;

       ret = db_config_get_catalog_flag(&flag);
       db_io_code_string(ret, mes);
       log_file_date("c_config_get_catalog_flag:f=%d,rc=%s", flag, mes);
    }

    void c_config_get_replicate_flag(void)
    {
       /* Test the 'config.get.replicate.flag' function. */

       char mes[50];
       int ret;
       int flag;

       ret = db_config_get_replicate_flag(&flag);
       db_io_code_string(ret, mes);
       log_file_date("c_config_get_replicate_flag:f=%d,rc=%s", flag, mes);
    }

    void c_config_get_version(void)
    {
       /* Test the 'config_get_version' function. */

       char version[50], mes[50];
       int ret;

       ret = db_config_get_version(version);
       db_io_code_string(ret, mes);
       log_file_date("c_config_get_version:v=%s,rc=%s", version, mes);
    }

    void c_get_open_table_list(void)
    {
       /* Test 'get_open_table_list' function. */

       char mes[50];
       int ret, nwords;

       if ((ret = db_get_open_table_list((char *)NULL, data)) == DBENG_OK)
          {
          nwords = ll_words(data, DBENG_LIST_DELIM);
          log_file_date("c_get_open_table_list:%d open table(s)", nwords);
          }

       db_io_code_string(ret, mes);
       log_file_date("c_get_open_table_list:rc=%s", mes);
    }

    void c_version(void)
    {
       /* Get 'Bbuuzzb' server version ID. Applies to multiuser
          only. */

    #ifndef MULTIUSER
       log_file_date("c_version:does not apply to single user");
       return;
    #else
       char mes[128];
       int ret;

       data[0] = EOS;
       ret = db_version(data);
       db_io_code_string(ret, mes);
       log_file_date("c_version:ver=%s,rc=%s", data, mes);
    #endif
    }

    void c_exist(void)
    {
       /* Test the 'exist' function. */

       char mes[128], fname[128];
       int test_prim, ret, exist_flag;

       /* pick a random number between 0 and 1 */

       test_prim = rnd(0, 1);

       if (test_prim)
          strcpy(fname, ds_prim);
       else
          strcpy(fname, "zzz");

       ret = db_exist(fname, &exist_flag);
       db_io_code_string(ret, mes);
       log_file_date("c_exist:fname=%s,exist_flag=%d,rc=%s", fname,
                     exist_flag, mes);
    }

    void c_get_catalog_list(void)
    {
       /* Test 'get_catalog_list' function. */

       char mes[50];
       int ret, nwords;

       if ((ret = db_get_catalog_list((char *)NULL, data)) == DBENG_OK)
          {
          nwords = ll_words(data, DBENG_LIST_DELIM);
          log_file_date("c_get_catalog_list:%d catalog entry/entries", nwords);
          }

       db_io_code_string(ret, mes);
       log_file_date("c_get_catalog_list:rc=%s", mes);
    }

    void c_sort(void)
    {
       /* Test the 'sort' command. */

       char mes[50], spec[5], mname[] = "c_sort";
       int ret, which_type;

       /* pick a random number between 0 and 3 */

       which_type = rnd(0, 3);

       switch(which_type)
          {
          case 0:
             /* just field 1 ascending */

             strcpy(spec, "1");
             break;

          case 1:
             /* field 1 descending */

             strcpy(spec, "1,d");
             break;

          case 2:
             /* field 1 and field two both ascending */

             strcpy(spec, "1^2");
             break;

          case 3:
             /* illegal */

             strcpy(spec, "1,z");
             break;
          };

       ret = db_sort(tid, spec);
       db_io_code_string(ret, mes);
       log_file_date("%s:spec=%s,rc=%s", mname, spec, mes);
    }

    void c_get_sort_mem(void)
    {
       /* Test the 'get.sort.mem' command. */

       char mes[50];
       long mem;
       int ret;

       ret = db_get_sort_max_mem(tid, &mem);
       db_io_code_string(ret, mes);
       log_file_date("c_get_sort_mem:sort mem=%ld,rc=%s", mem, mes);
    }

    void c_set_sort_mem(void)
    {
       /* Test the 'set.sort.mem' command. */

       char mes[50];
       long mem;
       int ret;

       /* generate a random long in the range 1700-200000 (actual allowable
          range is >= 2000) */

    #ifndef OS_DOS
       mem = (long)rnd(1700, 200000);
    #else
       mem = (long)rnd(1700, 32766);
    #endif
       ret = db_set_sort_max_mem(tid, mem);
       db_io_code_string(ret, mes);
       log_file_date("c_set_sort_mem:sort mem=%ld,rc=%s", mem, mes);
    }

    void c_get_sort_open_bin(void)
    {
       /* Test the 'get.sort.open.bin' command. */

       char mes[50];
       int max_bin;
       int ret;

       ret = db_get_sort_max_open_bin(tid, &max_bin);
       db_io_code_string(ret, mes);
       log_file_date("c_get_sort_open_bin:open bin=%d,rc=%s", max_bin, mes);
    }

    void c_set_sort_open_bin(void)
    {
       /* Test the 'set.sort.open.bin' command. */

       char mes[50];
       int max_bin;
       int ret;

       /* generate a random int in the range 0-29 (actual allowable
          range is >= 3) */

       max_bin = rnd(0, 29);
       ret = db_set_sort_max_open_bin(tid, max_bin);
       db_io_code_string(ret, mes);
       log_file_date("c_set_sort_open_bin:open_bin=%d,rc=%s", max_bin, mes);
    }

    void c_delete_field(void)
    {
       /* Test 'delete.field' function by deleting a random field. */

       char mes[50];
       int ret;
       int fnum;

       /* pick a random number between 0 and 254 for field number */

       fnum = rnd(0, 254);
       ret = db_delete_field(tid, fnum);
       db_io_code_string(ret, mes);
       log_file_date("c_delete_field:f=%d,rc=%s", fnum, mes);
    }

    void c_delete_subfield(void)
    {
       /* Test 'delete.subfield' function by deleting a random subfield. */

       char mes[50];
       int ret;
       int fnum, sfnum;

       /* pick a random number between 0 and 254 for field number
          and zero to 9 for subfield number */

       fnum = rnd(0, 254);
       sfnum = rnd(0, 9);
       ret = db_delete_subfield(tid, fnum, sfnum);
       db_io_code_string(ret, mes);
       log_file_date("c_delete_subfield:f=%d,sf=%d,rc=%s", fnum, sfnum, mes);
    }

    void c_delete_subsubfield(void)
    {
       /* Test 'delete.subsubfield' function by deleting a random subsubfield. */

       char mes[50];
       int ret;
       int fnum, sfnum, ssfnum;

       /* pick a random number between 0 and 254 for field number
          and zero to 9 for subfield and subsubfield number */

       fnum = rnd(0, 254);
       sfnum = rnd(0, 9);
       ssfnum = rnd(0, 9);
       ret = db_delete_subsubfield(tid, fnum, sfnum, ssfnum);
       db_io_code_string(ret, mes);
       log_file_date("c_delete_subsubfield:f=%d,sf=%d,ssf=%d,rc=%s", fnum, sfnum,
                     ssfnum, mes);
    }

    void c_trans_num(void)
    {
       /* Get 'Bbuuzzb' server transaction count. Applies to multiuser
          only. */

       char mname[] = "c_trans_num";

    #ifndef MULTIUSER
       log_file_date("%s:does not apply to single user", mname);
       return;
    #else
       char mes[128];
       long trans_num;
       int ret;

       ret = db_trans_num(&trans_num);
       db_io_code_string(ret, mes);
       log_file_date("%s:trans_num=%ld,rc=%s", mname, trans_num, mes);
    #endif
    }

    void c_connect_num(void)
    {
       /* Get 'Bbuuzzb' server connection count. Applies to multiuser
          only. */

       char mname[] = "c_connect_num";

    #ifndef MULTIUSER
       log_file_date("%s:does not apply to single user", mname);
       return;
    #else
       char mes[128];
       int connect_num;
       int ret;

       ret = db_connect_num(&connect_num);
       db_io_code_string(ret, mes);
       log_file_date("%s:connect_num=%d,rc=%s", mname, connect_num, mes);
    #endif
    }

    void c_get_autopack(void)
    {
       /* Test 'get_autopack' function. */

       char mes[50];
       int ret;
       int pval;

       ret = db_get_autopack(tid, &pval);
       db_io_code_string(ret, mes);
       log_file_date("c_get_autopack:p=%d,rc=%s", pval, mes);
    }

    void c_set_autopack(void)
    {
       /* Test 'set_autopack' function. */

       char mes[50];
       int ret;
       int pval;

       pval = rnd(0, 10);
       ret = db_set_autopack(tid, pval);
       db_io_code_string(ret, mes);
       log_file_date("c_set_autopack:p=%d,rc=%s", pval, mes);
    }

    void c_config_client_get_log(void)
    {
       /* Test the 'config_client_get_log' function. */

       char mname[] = "c_config_client_get_log";

    #ifndef MULTIUSER
       log_file_date("%s:does not apply to single user", mname);
       return;
    #else
       char *slog, mes[50];
       int ret;

       if ((slog = (char *)malloc(DBENG_PATH_LIMIT)) == (char *)NULL)
          {
          db_io_code_string(DBENG_MEMORY_FAIL, mes);
          log_file_date("%s:alloc fail 'slog',rc=%s", mname, mes);
          return;
          }

       if ((ret = db_config_client_get_log(slog)) != DBENG_OK)
          {
          db_io_code_string(ret, mes);
          log_file_date("%s:error getting config log,rc=%s", mname, mes);
          free(slog);
          return;
          }

       db_io_code_string(ret, mes);
       log_file_date("%s:log=%s,rc=%s", mname, slog, mes);
       free(slog);
    #endif
    }

    void c_config_client_get_log_flag(void)
    {
       /* Test the 'config_client_get_log_flag' function. */

       char mname[] = "c_config_client_get_log_flag";

    #ifndef MULTIUSER
       log_file_date("%s:does not apply to single user", mname);
       return;
    #else
       char mes[50];
       int ret;
       int flag;

       ret = db_config_client_get_log_flag(&flag);
       db_io_code_string(ret, mes);
       log_file_date("%s:f=%d,rc=%s", mname, flag, mes);
    #endif
    }

    void c_put_data(void)
    {
       /* Place a random number of digits into the 'data' string. */

       char ch;
       int ndigits;
       int i;

       /* generate between 1 and 100 digits */

       ndigits = rnd(1, 100);

       /* build */

       data[0] = EOS;

       for(i = 0; i < ndigits; i++)
          {
          ch = rnd(48, 57); /* random digit */
          data[i] = ch;
          }

       data[ndigits] = EOS;
    }

    void term_app(void)
    {
       // Prepare to terminate the application. Shutdown all IPC API's.

       db_end();

    #ifndef OS_DOS
       if (is_sys_log_active())
          sys_log_end();
    #endif

    #ifndef MULTIUSER
       // single user
    #ifdef DEBUG
       // with 'DEBUG' on
    #ifdef IPC_TCP
       // with TCP IPC method
       sloc_term_api();
    #ifdef OS_WIN32
       // under Windoze
       WSACleanup();
    #endif // Windoze
    #endif // TCP IPC
    #endif // DEBUG
    #else  // multiuser
    #ifdef IPC_TCP
       // with TCP IPC method
       sloc_term_api();
    #endif
    #ifdef OS_WIN32
       // under Windoze
       WSACleanup();
    #endif
    #endif

    #ifndef OS_DOS
       (void)appinit_remove_name();
    #endif

       if (is_log_active())
          log_end();
    }

/* [<][>][^][v][top][bottom][index][help] */