/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- dbeng_pack_table
- dbeng_open_systable
- dbeng_open_table
- dbeng_ll_open_table
- dbeng_close_table
- dbeng_goto_top
- dbeng_rewrite_recd
- dbeng_delete_recd
- dbeng_write_new_recd
- dbeng_write_string_recd
- dbeng_write_recd
- dbeng_new
- dbeng_get_rec
- dbeng_get_field
- dbeng_get_subfield
- dbeng_get_subsubfield
- dbeng_put_field
- dbeng_put_subfield
- dbeng_put_subsubfield
- dbeng_find
- dbeng_find_field
- dbeng_find_part
- dbeng_find_field_part
- dbeng_nfields
- dbeng_nsubfields
- dbeng_nsubsubfields
- dbeng_count_rec
- dbeng_rec_count
- dbeng_goto_record
- dbeng_get_recd
- dbeng_rec_resize
- dbeng_rec_size
- dbeng_field_size
- dbeng_subfield_size
- dbeng_subsubfield_size
- dbeng_rec_num
- dbeng_pos
- dbeng_set_pos
- dbeng_change_rec_flag
- dbeng_set_change_rec_flag
- dbeng_delete_flag
- dbeng_set_delete_flag
- dbeng_enf_change_rec_flag
- dbeng_set_enf_change_rec_flag
- dbeng_autopack
- dbeng_set_autopack
- dbeng_is_table_locked
- dbeng_set_is_table_locked
- dbeng_lock_table
- dbeng_unlock_table
- dbeng_tmp_systable
- dbeng_new_systable
- dbeng_new_table
- dbeng_ll_new_table
- dbeng_delete_table
- dbeng_open_table_list
- dbeng_exist
- dbeng_clear_table
- dbeng_ll_open
- dbeng_ll_close
- dbeng_is_systable
- dbeng_copy_table
- dbeng_record_header
- dbeng_put_which_field
- dbeng_put_which_subfield
- dbeng_put_which_subsubfield
- dbeng_ll_copy_table
- dbeng_delete_field
- dbeng_delete_subfield
- dbeng_delete_subsubfield
- dbeng_set_record_count
- dbeng_terminate
- dbeng_is_active_rec
- dbeng_initialize
- dbeng_get_tid
- dbeng_table_in_use
- dbeng_compare_field
- dbeng_atid_lookup
- dbeng_ferror
/* DBENG (Bbuuzzb) - A database engine. Library functions.
Rick Smereka, Copyright (C) 1995-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 Feb/95, Rick Smereka
Added call to 'setvbuf' to set I/O buffer size. Dec/96, Rick Smereka
Updated code to have same functionality as Pascal (Delphi) code.
Also ported to QNX V4.23a. Jan/97, Rick Smereka
Complete re-write removing all known errors. Changed to remove 'alias'
and add 'tid'. Oct/97, Rick Smereka
Added logic to support 'is_table_locked' flag. If this flag is
on, no read, write or file pointer movement will be allowed.
Nov/98, Rick Smereka
Ported to 32bit Windows under CodeWarrior V4.
Dec/98, Rick Smereka
Ported to HP-UX under GNU C V2.8.1.
Jan/99, Rick Smereka
Added function 'dbeng_ferror', changed function
'dbeng_get_recd' to use this new function. Fixed bug in
function 'dbeng_count_rec' that did not properly trap
an error from 'dbeng_get_recd'. Feb/99, Rick Smereka
Added functions 'dbeng_get_tmp_path' and 'dbeng_get_error_log'.
Moved these functions to 'dbengcfg.c' and renamed them. Modified
'dbeng_pack' to get the temporary path from function
'dbeng_config_get_tmp_path'. Modified function 'dbeng_ferror'
to get the log name (in the case of stand-alone compile)
from the function 'dbeng_config_get_log'.
Feb/99, Rick Smereka
Ported to Red Hat Linux 5.2, Jul/99, Rick Smereka
Added include of 'flsocket.h'. Mar/2000, Rick Smereka
Cleaned up debug messages. Apr/2000, Rick Smereka
Added function 'dbeng_open_table_list'. Jun/2001,
Rick Smereka
Added session table support. Oct/2001, Rick Smereka
Added system catalog support and implemented support for
new 'dbeng_table' member 'current_position'. Modified
function 'dbeng_pack_table' to goto the top of the table
after packing. Added new functions 'dbeng_ll_open' and
'dbeng_ll_close'. Changed function 'dbeng_set_pos' to
goto the top of the table before positioning.
Nov/2001, Rick Smereka
Added new functions 'dbeng_nsubfields', 'dbeng_subfield_size',
'dbeng_get_subfield', 'dbeng_put_subfield', 'dbeng_nsubsubfields',
'dbeng_subsubfield_size', 'dbeng_get_subsubfield' and
'dbeng_put_subsubfield'. Dec/2001, Rick Smereka
Added function 'dbeng_record_header'. Changed 'dbeng_get_recd' to
read and validate the record header through the new function.
Changed 'dbeng_delete_recd' to make sure that a valid record
is present before updating it. If the record position has been
changed (possible other user/tid packed the table changing some of
the record positions) 'dbeng_delete_recd' will return
'DBENG_RECORD_POSITION_CHANGED' along with forcing the file position
back to the top of the table. This situation should never happen
as 'dbeng_pack_table' and 'dbeng_delete_recd' have now been modified
to reconcile any other tid pointing to the record being modified.
Changed 'dbeng_write_string_recd' to maintain the start of record
file position and current file position instead of going to the
top of the table after the write of a record. Jan/2002, Rick Smereka
Added functions 'dbeng_open_systable', 'dbeng_ll_open_table',
'dbeng_new_systable', 'dbeng_ll_new_table' and
'dbeng_is_systable'. Placed calls to 'dbengrep_send' from the
functions 'dbeng_write_new_recd', 'dbeng_write_string_recd',
'dbeng_delete_recd' and 'dbeng_pack_table'. Feb/2002, Rick Smereka
Changed function 'dbeng_ll_new_table' to create the new table only
in single user mode as the catalog module 'dbeng_catalog_new_table'
will create the table in multiuser mode. Mar/2002, Rick Smereka
Changed function 'dbeng_record_header' to be private. Apr/2002,
Rick Smereka
Changed function 'dbeng_get_tid' to obtain the next tid based
on the number of current tables in use. Added private functions
'dbeng_put_which_field', 'dbeng_put_which_subfield' and
'dbeng_put_which_subsubfield'. Modified functions
'dbeng_put_field', 'dbeng_put_subfield' and
'dbeng_put_subsubfield' to call their respective
'dbeng_put_which' function. Added function 'dbeng_exist'.
May/2002, Rick Smereka
Added functions 'dbeng_ll_copy_table' and 'dbeng_clear_table'
and 'dbeng_copy_table'. Jun/2002, Rick Smereka
Changed function 'dbeng_ferror' to obtain the application name
(in the case of multi-user [database server]) by calling
'appinit_get_name'. Jul/2002, Rick Smereka
Added a parameter to the function 'dbeng_open_table_list'.
Aug/2002, Rick Smereka
Added function 'dbeng_tmp_systable' and modified 'dbeng_pack_table'
to create a new system table using 'dbeng_tmp_systable'. Sep/2002,
Rick Smereka
Added include of 'dbengsrt.h'. Added initialization code for new
'dbeng_table' members 'sort_max_open_bin' and 'sort_max_mem' in
function 'dbeng_ll_open_table'. Ported to Debian Linux.
Nov/2002, Rick Smereka
Fixed bug in 'dbeng_tmp_systable' that caused a memory leak.
Added private function 'dbeng_compare_field' and modified
functions 'dbeng_find_field' and 'dbeng_find' to use this
new function. Added functions 'dbeng_delete_field',
'dbeng_delete_subfield' and 'dbeng_delete_subsubfield'.
Mar/2003, Rick Smereka
Changed function 'dbeng_get_recd' to goto the top of the
table when the attempt to read a record header results in
any error code (anything other than 'DBENG_OK'). Jun/2003,
Rick Smereka
Changed counting logic in 'dbeng_count_rec' and added an additional
parameter. Changed calls to 'dbeng_count_rec'. Changed all references
to the 'dbeng_table' member 'record_count' to either the active
count or the deleted record count. Changed function 'dbeng_rec_count'
by adding an additional parameter. Dec/2003, Rick Smereka
Added save of 'process_deleted' flag, force of flag to high
before count in 'dbeng_count_rec' and restore of flag after
count. Jan/2004, Rick Smereka
Added function 'dbeng_set_record_count'. Feb/2004,
Rick Smereka
Modified function 'dbeng_ll_open_table' to acquire table
catalog details from function 'dbeng_catalog_table_details'.
Added functions 'dbeng_autopack' and 'dbeng_set_autopack'.
Added logic to perform automatic pack in function
'dbeng_delete_recd' if the autopack threshold is exceeded.
Changed all logging calls from 'sys_log' to 'logman'.
Modified function 'dbeng_ferror' to use 'logman' functions.
Any application linking with this API should register its
name with the function 'appinit_register_name'. The function
'dbeng_ferror' obtains the application name by calling the
function 'appinit_get_name'. Mar/2004, Rick Smereka
Fixed bug in 'dbeng_ll_new_table' that caused a 'segment fault'
crash because the output table name was not big enough. Changed
'dbeng_write_recd' to detect when writing a record already marked
for deletion. In this case, a new record will be created.
Jan/2005, Rick Smereka
Plugged memory leak in 'dbeng_ll_open_table' when the open failed
due to no catalog entry. Feb/2005, Rick Smereka
Modified 'dbeng_ll_new_table' to only open the new table when the
passed tid flag is a positive number. Mar/2006, Rick Smereka */
#include "stdhead.h"
#include "dbmess.h"
#include "dbeng.h"
#include "dbiocode.h"
#include "dbengcfg.h"
#include "dbengsrt.h"
#include "dbengcat.h"
#ifdef MULTIUSER
#include "dbengses.h"
#ifdef IPC_TCP
#include "dbengrep.h"
#endif
#endif
/* global data */
/* pointer to head of open table link list */
struct dbeng_table *dbeng_head;
/* number of tables in use */
int dbeng_table_count;
/* private functions */
static int dbeng_ll_open_table(char *, int *, int);
static int dbeng_ll_new_table(char *, int *, int);
static int dbeng_record_header(struct dbeng_table *, int *, char *);
static int dbeng_put_which_field(struct dbeng_table *, int, int *);
static int dbeng_put_which_subfield(struct dbeng_table *, int, int , int *,
int *);
static int dbeng_put_which_subsubfield(struct dbeng_table *, int, int, int,
int *, int *, int *);
static int dbeng_table_in_use(char *);
static int dbeng_ll_copy_table(struct dbeng_table *, struct dbeng_table *);
static int dbeng_compare_field(char *, char *, int, int *);
int dbeng_pack_table(struct dbeng_table *ot)
{
/* Pack a table by copying only active records. Function
returns 'DBENG_OK' upon success, an error code otherwise. */
struct dbeng_table *dest_table;
char *dest_table_name;
char mname[] = "dbeng_pack_table";
int ret, tid, delete_flag, len;
#ifdef MULTIUSER
#ifdef IPC_TCP
int rep_flag;
#endif
#endif
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);
/* check for locked table */
if (ot->is_table_locked)
{
dbeng_io_code_log(mname, "locked", DBENG_TABLE_LOCKED);
return(DBENG_TABLE_LOCKED);
}
/* check for changed record */
if (ot->enforce_change_rec_flag && ot->change_rec_flag)
{
dbeng_io_code_log(mname, "record changed", DBENG_RECORD_CHANGED);
return(DBENG_RECORD_CHANGED);
}
if ((ret = dbeng_tmp_systable(&tid)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_tmp_systable", ret);
return(ret);
}
/* fetch link list pointer from tid */
if ((dest_table = dbeng_atid_lookup(tid)) == NULL)
{
logman("%s:cannot locate tmp table[%d]", mname, tid);
return(DBENG_CANNOT_CREATE_TABLE);
}
logman("%s:output tmp table is %s", mname, dest_table->name);
len = strlen(dest_table->name);
if ((dest_table_name = (char *)malloc(len + 1)) == (char *)NULL)
{
dbeng_io_code_log(mname, "alloc fail[dest_table_name]",
DBENG_MEMORY_FAIL);
return(DBENG_MEMORY_FAIL);
}
strcpy(dest_table_name, dest_table->name);
/* force source 'process_deleted' flag down (save prev value) */
delete_flag = ot->process_deleted;
ot->process_deleted = FALSE;
/* copy source to destination */
if ((ret = dbeng_ll_copy_table(ot, dest_table)) != DBENG_OK)
{
(void)dbeng_close_table(dest_table);
unlink(dest_table_name);
ot->process_deleted = delete_flag;
dbeng_io_code_log(mname, "bad ret from dbeng_ll_copy_table", ret);
free(dest_table_name);
return(ret);
}
// fix-up record counts
ot->active_record_count = dest_table->active_record_count;
ot->deleted_record_count = 0L;
/* close output (temporary) table */
if ((ret = dbeng_close_table(dest_table)) != DBENG_OK)
{
unlink(dest_table_name);
ot->process_deleted = delete_flag;
dbeng_io_code_log(mname, "error closing tmp table", ret);
free(dest_table_name);
return(ret);
}
/* close source table (but retain table structure) */
if ((ret = dbeng_ll_close(ot)) != DBENG_OK)
{
unlink(dest_table_name);
ot->process_deleted = delete_flag;
dbeng_io_code_log(mname, "error closing source table", ret);
free(dest_table_name);
return(ret);
}
/* delete source table */
unlink(ot->name);
/* rename temporary table to source */
if (!qrename(dest_table_name, ot->name))
{
ot->process_deleted = delete_flag;
logman("%s:error renaming table", mname);
free(dest_table_name);
return(DBENG_RENAME_ERROR);
}
free(dest_table_name);
if ((ret = dbeng_ll_open(ot)) != DBENG_OK)
{
dbeng_io_code_log(mname, "error re-opening file", DBENG_UNABLE_TO_OPEN);
return(DBENG_UNABLE_TO_OPEN);
}
/* since we are now at the bottom of the table, goto top */
(void)dbeng_goto_top(ot);
// fix-up record count
if ((ret = dbeng_set_record_count(ot)) != DBENG_OK)
{
dbeng_io_code_log(mname, "error setting record count",
DBENG_INTERNAL_ERROR);
return(DBENG_INTERNAL_ERROR);
}
/* replicate command if requested */
#ifdef MULTIUSER
#ifdef IPC_TCP
(void)dbeng_config_get_replicate_flag(&rep_flag);
if (rep_flag && ot->rep_list != DBENG_ROT_NULL)
if ((ret = dbengrep_send(ot, DBENG_SEND_REPLICATE_PACK, (char *)NULL))
!= DBENG_OK)
logman("%s:replication failed,rc=%d", mname, ret);
#endif
#endif
dbeng_io_code_log(mname, "normal exit", DBENG_OK);
return(DBENG_OK);
}
int dbeng_open_systable(char *fname, int *tid)
{
/* Open a system table. At the moment, a system table is one of:
- temporary table
- session table
- catalog
This function behaves just like 'dbeng_open_table' except
that the physical file is always left open. Function returns
a 'dbeng' code. */
char mname[] = "dbeng_open_systable";
int ret;
if (fname == (char *)NULL || !strlen(fname))
{
dbeng_io_code_log(mname, "fname parameter error",
DBENG_INVALID_FILE_NAME);
return(DBENG_INVALID_FILE_NAME);
}
logman("%s:enter,fname=%s", mname, fname);
if (tid == (int *)NULL)
{
dbeng_io_code_log(mname, "null[tid]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
*tid = 0;
/* open the table using 'dbeng_ll_open_table' */
if ((ret = dbeng_ll_open_table(fname, tid, TRUE)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_ll_open_table", ret);
return(ret);
}
dbeng_io_code_log(mname, "normal exit", DBENG_OK);
return(DBENG_OK);
}
int dbeng_open_table(char *fname, int *tid)
{
/* Open a table. Function returns the table 'tid'
upon success. Function returns a 'dbeng' code. */
char mname[] = "dbeng_open_table";
int ret;
if (fname == (char *)NULL || !strlen(fname))
{
dbeng_io_code_log(mname, "fname parameter error",
DBENG_INVALID_FILE_NAME);
return(DBENG_INVALID_FILE_NAME);
}
logman("%s:enter,fname=%s", mname, fname);
if (tid == (int *)NULL)
{
dbeng_io_code_log(mname, "null[tid]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
*tid = 0;
/* open the table using 'dbeng_ll_open_table' */
if ((ret = dbeng_ll_open_table(fname, tid, FALSE)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_ll_open_table", ret);
return(ret);
}
dbeng_io_code_log(mname, "normal exit", DBENG_OK);
return(DBENG_OK);
}
static int dbeng_ll_open_table(char *fname, int *tid, int systable_flag)
{
/* Open a table. Table ID is returned in 'tid' upon success.
If the system catalog flag is on, only logical table names
listed in the system catalog will succeed unless the name
is prefixed with the 'DBENG_CATALOG_FNAME_IND' character.
Function returns 'DBENG_OK' upon success, error code otherwise.
Note that if the code returned is 'DBENG_FILE_DATA_ERROR',
the 'tid' is still loaded and the file is left open. */
struct dbeng_table *ot;
struct dbeng_table *rov;
struct dbengcat_details *det;
char mname[] = "dbeng_ll_open_table";
int ot_size, session_flag, rep_flag, ret;
int name_type, done = FALSE;
logman("%s:enter", mname);
if (fname == (char *)NULL || !strlen(fname))
{
dbeng_io_code_log(mname, "fname parameter error",
DBENG_INVALID_FILE_NAME);
return(DBENG_INVALID_FILE_NAME);
}
if (tid == (int *)NULL)
{
dbeng_io_code_log(mname, "null[tid]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (systable_flag != TRUE && systable_flag != FALSE)
{
dbeng_io_code_log(mname, "bad flag[systable_flag]",
DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
*tid = 0;
ot_size = sizeof(struct dbeng_table);
if ((ot = malloc(ot_size)) == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "alloc fail[ot]", DBENG_MEMORY_FAIL);
return(DBENG_MEMORY_FAIL);
}
ot->handle = (FILE *)NULL;
// prepare to load table catalog details
if ((ret = dbeng_catalog_init_table_details(fname, systable_flag, &det)) !=
DBENG_OK)
{
dbeng_io_code_log(mname,
"bad rc from dbeng_catalog_init_table_details", ret);
free(ot);
return(ret);
}
// load table catalog details
if ((ret = dbeng_catalog_table_details(det)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_catalog_table_details", ret);
(void)dbeng_catalog_term_table_details(&det);
free(ot);
return(ret);
}
#ifdef MULTIUSER
(void)dbeng_config_get_session_flag(&session_flag);
ot->rep_list = DBENG_ROT_NULL;
#endif
/* file name is stored in original case and is compared
case sensitive */
if ((ot->name = malloc(strlen(det->physical_name) + 1)) == (char *)NULL)
{
free(ot);
(void)dbeng_catalog_term_table_details(&det);
dbeng_io_code_log(mname, "alloc fail[ot->name]", DBENG_MEMORY_FAIL);
return(DBENG_MEMORY_FAIL);
}
strcpy(ot->name, det->physical_name);
if ((ret = dbeng_ll_open(ot)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_ll_open", ret);
free(ot->name);
free(ot);
(void)dbeng_catalog_term_table_details(&det);
return(ret);
}
ot->next = DBENG_OT_NULL; // end of link list
ot->rec = (char *)NULL; // no current record
ot->change_rec_flag = FALSE; // no change in record
ot->enforce_change_rec_flag = FALSE; // do not enforce 'change_rec_flag'
ot->record_number = 0L; // no current record
ot->orig_position = -1L; // no start rec file pointer position
ot->current_position = 0L; // current pos at top of table
ot->process_deleted = FALSE; // do not process deleted records
ot->is_table_locked = FALSE; // table is not read/write locked
ot->is_systable = systable_flag; // set system table flag
/* if its a system table, use the default autopack threshold
otherwise use the threshold given in the catalog (if present) */
ot->autopack = systable_flag ? DBENG_SYSTABLE_MAX_DELETED : det->apack;
ot->sort_max_open_bin = DBENGSRT_MAX_OPEN_BIN; // max open bin during sort
ot->sort_max_mem = DBENGSRT_MAX_SORT_ALLOC; // max mem alloc during sort
/* set head of list if first file open */
if (dbeng_head == DBENG_OT_NULL)
dbeng_head = ot;
else
{
/* insert new table at end of link list */
rov = dbeng_head;
while(!done)
{
if (rov->next == DBENG_OT_NULL)
{
rov->next = ot;
done = TRUE;
}
else
rov = rov->next;
}
}
ot->tid = dbeng_get_tid();
*tid = ot->tid;
if ((ret = dbeng_count_rec(ot, &ot->active_record_count,
&ot->deleted_record_count)) != DBENG_OK)
{
(void)dbeng_catalog_term_table_details(&det);
return(ret);
}
(void)dbeng_goto_top(ot);
dbeng_table_count++;
#ifdef MULTIUSER
/* if session table is active, physically close the file
unless it is a system table */
if (session_flag && !systable_flag)
if ((ret = dbeng_ll_close(ot)) != DBENG_OK)
dbeng_io_code_log(mname, "error closing table", ret);
#ifdef IPC_TCP
/* if replication is active and a catalog table name was used
to open the table, load replication details from
catalog into replication link list (do not allow
replication of any system table) */
(void)dbeng_config_get_replicate_flag(&rep_flag);
if (rep_flag && fname[0] != DBENG_CATALOG_FNAME_IND && !ot->is_systable)
if ((ret = dbengrep_rll_load(ot, det->rep_list)) != DBENG_OK)
{
if (ret != DBENG_NO_REPLICATION_ENTRY && ret !=
DBENG_NO_CATALOG_ENTRY)
{
logman("%s:exit:bad rc[%d] from dbengrep_rll_load[%d]",
mname, ret, rov->tid);
(void)dbeng_catalog_term_table_details(&det);
return(ret);
}
}
#endif
#endif
if ((ret = dbeng_catalog_term_table_details(&det)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from "
"dbeng_catalog_term_table_details", ret);
return(ret);
}
logman("%s:normal exit", mname);
return(DBENG_OK);
}
int dbeng_close_table(struct dbeng_table *table)
{
/* Close a table. Function returns 'DBENG_OK' upon success,
error code otherwise. */
struct dbeng_table *rov;
struct dbeng_table *prev;
char mname[] = "dbeng_close_table";
int ret, session_flag, rep_flag, done = FALSE;
if (table == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[table]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
logman("%s:enter:tid=%d", mname, table->tid);
if (table->enforce_change_rec_flag && table->change_rec_flag)
{
dbeng_io_code_log(mname, "record changed", DBENG_RECORD_CHANGED);
return(DBENG_RECORD_CHANGED);
}
#ifdef MULTIUSER
(void)dbeng_config_get_session_flag(&session_flag);
if (session_flag && !table->is_systable)
if ((ret = dbeng_session_delete(table->tid)) != DBENG_OK)
dbeng_io_code_log(mname, "bad rc from dbeng_session_delete", ret);
#ifdef IPC_TCP
(void)dbeng_config_get_replicate_flag(&rep_flag);
if (rep_flag && !table->is_systable)
if ((ret = dbengrep_rll_delete_all(table)) != DBENG_OK)
dbeng_io_code_log(mname, "bad rc from dbengrep_rll_delete", ret);
#endif
#endif
rov = table;
rov->change_rec_flag = -1; /* mark this table to close */
rov = dbeng_head; /* goto top of link list */
prev = DBENG_OT_NULL;
done = FALSE;
/* loop to locate the previous table in the link list, close the
appropiate table and de-allocate all memory used by the
table structure */
while(!done)
{
/* this should never happen but just in case */
if (rov == DBENG_OT_NULL)
{
logman("%s:unexpected rov NULL", mname);
break;
}
if (rov->change_rec_flag == -1)
{
if (prev == DBENG_OT_NULL)
if (rov->next == DBENG_OT_NULL)
dbeng_head = DBENG_OT_NULL;
else
dbeng_head = rov->next;
else
prev->next = rov->next;
if ((ret = dbeng_ll_close(rov)) != DBENG_OK)
dbeng_io_code_log(mname, "warning:problem closing table", ret);
free(rov->name);
if (dbeng_is_active_rec(rov) == DBENG_OK)
free(rov->rec);
free(rov);
done = TRUE;
}
else
{
prev = rov;
rov = rov->next;
}
}
dbeng_table_count--;
if (!done)
{
dbeng_io_code_log(mname, "normal exit", DBENG_INTERNAL_ERROR);
return(DBENG_INTERNAL_ERROR);
}
logman("%s:normal exit", mname);
return(DBENG_OK);
}
int dbeng_goto_top(struct dbeng_table *ot)
{
/* Reposition table at the top, with no current record. Function
returns 'DBENG_OK' upon success, an error code otherwise. */
char mname[50];
strcpy(mname, "dbeng_goto_top");
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[table]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
/* logman("%s:enter:name=%s", mname, ot->name); */
if (ot->enforce_change_rec_flag && ot->change_rec_flag)
{
dbeng_io_code_log(mname, "record changed", DBENG_RECORD_CHANGED);
return(DBENG_RECORD_CHANGED);
}
rewind(ot->handle);
if (dbeng_is_active_rec(ot) == DBENG_OK)
free(ot->rec);
ot->rec = (char *)NULL;
ot->record_number = 0L;
ot->orig_position = -1L;
ot->current_position = 0L;
ot->change_rec_flag = FALSE;
/* logman("%s:normal exit", mname); */
return(DBENG_OK);
}
int dbeng_rewrite_recd(struct dbeng_table *ot)
{
/* Rewrite an existing record. Old record will be marked for
deletion and a new record will be written. Function returns
'DBENG_OK' upon success, an error code otherwise. */
struct dbeng_table tmp;
char mname[50];
int rec_size;
int ret, enf_change_rec_flag;
strcpy(mname, "dbeng_rewrite_recd");
logman("%s:enter", mname);
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
/* make sure there is an already existing record */
if (ot->orig_position == -1L || ot->record_number == 0L)
{
dbeng_io_code_log(mname, "no current record", DBENG_NO_EXISTING_RECORD);
return(DBENG_NO_EXISTING_RECORD);
}
// check for locked table
if (ot->is_table_locked)
{
dbeng_io_code_log(mname, "table is locked", DBENG_TABLE_LOCKED);
return(DBENG_TABLE_LOCKED);
}
/* save current record values as they are destroyed by
the delete record function */
rec_size = strlen(ot->rec);
if ((tmp.rec = malloc(rec_size + 1)) == NULL)
{
dbeng_io_code_log(mname, "alloc fail[tmp.rec]", DBENG_MEMORY_FAIL);
return(DBENG_MEMORY_FAIL);
}
strcpy(tmp.rec, ot->rec);
tmp.record_number = ot->record_number;
tmp.orig_position = ot->orig_position;
tmp.current_position = ot->current_position;
/* force 'enforce_change_rec_flag' down as the delete
function checks this */
enf_change_rec_flag = ot->enforce_change_rec_flag;
ot->enforce_change_rec_flag = FALSE;
ret = dbeng_delete_recd(ot);
if (ret != DBENG_OK)
{
dbeng_io_code_log(mname, "bad ret[delete_recd]", ret);
free(tmp.rec);
ot->enforce_change_rec_flag = enf_change_rec_flag;
return(ret);
}
/* reload record values */
ret = dbeng_rec_resize(ot, rec_size);
if (ret != DBENG_OK)
{
dbeng_io_code_log(mname, "resize fail", ret);
free(tmp.rec);
ot->enforce_change_rec_flag = enf_change_rec_flag;
return(ret);
}
strcpy(ot->rec, tmp.rec);
ot->record_number = tmp.record_number;
ot->orig_position = tmp.orig_position;
ot->current_position = tmp.current_position;
free(tmp.rec);
ret = dbeng_write_new_recd(ot);
ot->enforce_change_rec_flag = enf_change_rec_flag;
dbeng_io_code_log(mname, "normal exit", ret);
return(ret);
}
int dbeng_delete_recd(struct dbeng_table *ot)
{
/* Mark the current record for deletion. Function returns
'DBENG_OK' upon success, an error code otherwise. */
struct dbeng_table *rov;
char mname[] = "dbeng_delete_recd";
char rm[2], status;
int ret, len, rep_flag;
logman("%s:enter", mname);
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (ot->record_number == 0L || ot->orig_position == -1L)
{
dbeng_io_code_log(mname, "no current record", DBENG_NO_EXISTING_RECORD);
return(DBENG_NO_EXISTING_RECORD);
}
if (ot->enforce_change_rec_flag && ot->change_rec_flag)
{
dbeng_io_code_log(mname, "record changed", DBENG_RECORD_CHANGED);
return(DBENG_RECORD_CHANGED);
}
// check for locked table
if (ot->is_table_locked)
{
dbeng_io_code_log(mname, "table is locked", DBENG_TABLE_LOCKED);
return(DBENG_TABLE_LOCKED);
}
/* goto the start of the current record */
fseek(ot->handle, ot->orig_position, 0);
/* verify that there is a valid record here */
if ((ret = dbeng_record_header(ot, &len, &status)) != DBENG_OK)
{
dbeng_io_code_log(mname, "record header invalid,going to top", ret);
/* since there no longer is a current reocrd here, goto top */
(void)dbeng_goto_top(ot);
return(DBENG_RECORD_POSITION_CHANGED);
}
/* go back to the start of the record */
fseek(ot->handle, ot->orig_position, 0);
/* rewrite the first byte of the record */
rm[0] = 'D';
rm[1] = EOS;
if (fwrite(rm, 1, 1, ot->handle) != 1)
{
dbeng_io_code_log(mname, "write error on delete mark", DBENG_WRITE_FAIL);
return(DBENG_WRITE_FAIL);
}
#ifdef MULTIUSER
/* if another tid is also pointing to the same record,
tell that tid that this record is now deleted by
setting the record number to zero which will cause
'dbeng_write_recd' to write a new record */
rov = dbeng_head;
while(rov != DBENG_OT_NULL)
{
if (ot->tid != rov->tid && !strcmp(ot->name, rov->name))
if (ot->orig_position == rov->orig_position)
{
logman("%s:another tid using record,setting rn to zero:"
"tid=%d,ltid=%d,pos=%ld", mname, ot->tid, rov->tid,
rov->orig_position);
rov->record_number = 0;
}
rov = rov->next;
}
#ifdef IPC_TCP
/* replicate if requested */
(void)dbeng_config_get_replicate_flag(&rep_flag);
if (rep_flag && ot->rep_list != DBENG_ROT_NULL)
if ((ret = dbengrep_send(ot, DBENG_SEND_REPLICATE_DELETE, (char *)NULL))
!= DBENG_OK)
logman("%s:replication failed,rc=%d", mname, ret);
#endif
#endif
ot->active_record_count--;
ot->deleted_record_count++;
ot->change_rec_flag = FALSE;
// pack if autopack threshold is exceeded
if (ot->autopack && ot->deleted_record_count >= ot->autopack)
{
logman("%s:autopack threshold exceeded,autopacking", mname);
if ((ret = dbeng_pack_table(ot)) != DBENG_OK)
{
dbeng_io_code_log(mname, "error autopacking", ret);
return(ret);
}
}
else
{
// fix-up record count
if ((ret = dbeng_set_record_count(ot)) != DBENG_OK)
{
dbeng_io_code_log(mname, "error setting record count",
DBENG_INTERNAL_ERROR);
return(DBENG_INTERNAL_ERROR);
}
}
/* since file position is now unknown, goto top of file */
(void)dbeng_goto_top(ot);
logman("%s:normal exit", mname);
return(DBENG_OK);
}
int dbeng_write_new_recd(struct dbeng_table *ot)
{
/* Write new record. Function returns 'DBENG_OK' upon success,
error code otherwise. No regard is given to an already existing
record. If you need to rewrite, use 'dbeng_rewrite_recd'
instead. */
char header[DBENG_REC_HEAD_SIZE + 1];
char rm[2];
char mname[50];
int ret, len_with_head, len_no_head, rep_flag;
strcpy(mname, "dbeng_write_new_recd");
logman("%s:enter", mname);
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (dbeng_is_active_rec(ot) == DBENG_NO_RECORD)
{
dbeng_io_code_log(mname, "no current record", DBENG_NO_RECORD);
return(DBENG_NO_RECORD);
}
// check for locked table
if (ot->is_table_locked)
{
dbeng_io_code_log(mname, "table is locked", DBENG_TABLE_LOCKED);
return(DBENG_TABLE_LOCKED);
}
len_no_head = strlen(ot->rec);
fseek(ot->handle, 0L, 2); /* goto end of table */
ot->orig_position = ftell(ot->handle);
len_with_head = len_no_head + 1;
sprintf(header, "A%010d%c", len_with_head, DBENG_FM);
sprintf(rm, "%c", DBENG_RM);
if (fwrite(header, 1, DBENG_REC_HEAD_SIZE, ot->handle) !=
DBENG_REC_HEAD_SIZE)
{
dbeng_io_code_log(mname, "write fail on rec header",
DBENG_WRITE_FAIL);
return(DBENG_WRITE_FAIL);
}
if (fwrite(ot->rec, 1, len_no_head, ot->handle) != len_no_head)
{
dbeng_io_code_log(mname, "write fail on rec contents",
DBENG_WRITE_FAIL);
return(DBENG_WRITE_FAIL);
}
if (fwrite(rm, 1, 1, ot->handle) != 1)
{
dbeng_io_code_log(mname, "write fail on rec mark", DBENG_WRITE_FAIL);
return(DBENG_WRITE_FAIL);
}
++ot->record_number;
++ot->active_record_count;
ot->change_rec_flag = FALSE;
// fix-up record count
if ((ret = dbeng_set_record_count(ot)) != DBENG_OK)
{
dbeng_io_code_log(mname, "error setting record count",
DBENG_INTERNAL_ERROR);
return(DBENG_INTERNAL_ERROR);
}
#ifdef MULTIUSER
#ifdef IPC_TCP
/* replicate this change if requested */
(void)dbeng_config_get_replicate_flag(&rep_flag);
if (rep_flag && ot->rep_list != DBENG_ROT_NULL)
if ((ret = dbengrep_send(ot, DBENG_SEND_REPLICATE_WRITE, ot->rec))
!= DBENG_OK)
logman("%s:replication failed,rc=%d", mname, ret);
#endif
#endif
/* since file position is at end of file, goto top */
(void)dbeng_goto_top(ot);
logman("%s:normal exit", mname);
return(DBENG_OK);
}
int dbeng_write_string_recd(struct dbeng_table *ot, char *rec)
{
/* Write new record from the contents of 'rec'. Unlike
'dbeng_write_new_recd', this function does not
force the record pointer to the top of the table.
Function returns
'DBENG_OK' upon success, an error code otherwise. */
char header[DBENG_REC_HEAD_SIZE + 1];
char rm[2];
char mname[] = "dbeng_write_string_recd";
int ret, len_with_head, len_no_head, rep_flag;
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (rec == NULL || !strlen(rec))
{
dbeng_io_code_log(mname, "null[rec]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
/* logman("%s:enter", mname); */
len_no_head = strlen(rec);
fseek(ot->handle, 0L, 2); /* goto end of table */
ot->orig_position = ftell(ot->handle);
len_with_head = len_no_head + 1;
sprintf(header, "A%010d%c", len_with_head, DBENG_FM);
sprintf(rm, "%c", DBENG_RM);
if (fwrite(header, 1, DBENG_REC_HEAD_SIZE, ot->handle) !=
DBENG_REC_HEAD_SIZE)
{
dbeng_io_code_log(mname, "write fail on rec header",
DBENG_WRITE_FAIL);
return(DBENG_WRITE_FAIL);
}
if (fwrite(rec, 1, len_no_head, ot->handle) != len_no_head)
{
dbeng_io_code_log(mname, "write fail on rec contents",
DBENG_WRITE_FAIL);
return(DBENG_WRITE_FAIL);
}
if (fwrite(rm, 1, 1, ot->handle) != 1)
{
dbeng_io_code_log(mname, "write fail on rec mark", DBENG_WRITE_FAIL);
return(DBENG_WRITE_FAIL);
}
++ot->active_record_count;
ot->change_rec_flag = FALSE;
ot->current_position = ftell(ot->handle);
// fix-up record count
if ((ret = dbeng_set_record_count(ot)) != DBENG_OK)
{
dbeng_io_code_log(mname, "error setting record count",
DBENG_INTERNAL_ERROR);
return(DBENG_INTERNAL_ERROR);
}
#ifdef MULTIUSER
#ifdef IPC_TCP
/* replicate this change if requested */
(void)dbeng_config_get_replicate_flag(&rep_flag);
if (rep_flag && ot->rep_list != DBENG_ROT_NULL)
if ((ret = dbengrep_send(ot, DBENG_SEND_REPLICATE_WRITE, rec))
!= DBENG_OK)
logman("%s:replication failed,rc=%d", mname, ret);
#endif
#endif
/* logman("%s:normal exit", mname); */
return(DBENG_OK);
}
int dbeng_write_recd(struct dbeng_table *ot)
{
/* Write a new reocrd or rewrite an existing record depending on
the table record counter and the current record status (if any).
The record contents must already
be loaded and if a record exists, the file pointer must be
at the record. Function returns 'DBENG_OK' upon success,
an error code otherwise. */
char mname[] = "dbeng_write_recd";
int ret;
logman("%s:enter", mname);
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (dbeng_is_active_rec(ot) == DBENG_NO_RECORD)
{
dbeng_io_code_log(mname, "no current rec", DBENG_NO_RECORD);
return(DBENG_NO_RECORD);
}
// check for locked table
if (ot->is_table_locked)
{
dbeng_io_code_log(mname, "table is locked", DBENG_TABLE_LOCKED);
return(DBENG_TABLE_LOCKED);
}
// if there is not a current record in memory write a new one
if (!ot->record_number)
{
logman("%s:writing a new record", mname);
ret = dbeng_write_new_recd(ot);
}
else
{
// if the current record status is 'deleted', write a new record
if (!ot->record_status)
{
logman("%s:record already marked for deletion,writing a new rec",
mname);
ret = dbeng_write_new_recd(ot);
}
else
{
// re-write existing record
logman("%s:rewriting existing record", mname);
ret = dbeng_rewrite_recd(ot);
}
}
dbeng_io_code_log(mname, "normal exit", ret);
return(ret);
}
int dbeng_new(struct dbeng_table *ot)
{
/* Initialize for a new record. Note that if the current
record has changed and we are enforcing 'change_rec_flag,
the function will return that code and the initialization will
not take place. */
char mname[50];
strcpy(mname, "dbeng_new");
logman("%s:enter", mname);
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (ot->enforce_change_rec_flag && ot->change_rec_flag)
{
dbeng_io_code_log(mname, "record changed", DBENG_RECORD_CHANGED);
return(DBENG_RECORD_CHANGED);
}
if (dbeng_is_active_rec(ot) == DBENG_OK)
free(ot->rec);
ot->rec = (char *)NULL;
ot->record_number = 0L;
ot->orig_position = -1L;
ot->current_position = 0L;
ot->change_rec_flag = FALSE;
logman("%s:normal exit", mname);
return(DBENG_OK);
}
int dbeng_get_rec(struct dbeng_table *table, char *rec_out)
{
/* Copy and return the current record into 'rec_out' which
must be already allocated large enough to hold the record.
Function returns 'DBENG_OK' upon success, an error code
otherwise. */
char mname[50];
int ret;
strcpy(mname, "dbeng_get_rec");
logman("%s:enter", mname);
if (table == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[table]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (rec_out == NULL)
{
dbeng_io_code_log(mname, "null[rec_out]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
rec_out[0] = EOS;
if ((ret = dbeng_is_active_rec(table)) != DBENG_OK)
{
dbeng_io_code_log(mname, "no current rec", ret);
return(ret);
}
strcpy(rec_out, table->rec);
logman("%s:normal exit", mname);
return(DBENG_OK);
}
int dbeng_get_field(struct dbeng_table *table, char *field_out,
int field_num)
{
/* Obtain the 'field_num' field in the record specified by
'table'. Function returns 'DBENG_OK' on success,
error code otherwise. Note that the caller must allocate
enough memory in 'field_out' to copy the field contents. */
char mname[50];
int nwords;
strcpy(mname, "dbeng_get_field");
if (table == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[table]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (field_out == NULL)
{
dbeng_io_code_log(mname, "null[field_out]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
field_out[0] = EOS;
if (field_num <= 0)
{
dbeng_io_code_log(mname, "out of range[field_num]",
DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
/* logman("%s:enter", mname); */
/* if no table or no current record, error */
if (table == DBENG_OT_NULL || dbeng_is_active_rec(table) == DBENG_NO_RECORD)
{
dbeng_io_code_log(mname, "no table or current record", DBENG_NO_RECORD);
return(DBENG_NO_RECORD);
}
nwords = ll_words(table->rec, DBENG_FM);
/* if field is out of range, error */
if (field_num > nwords)
{
logman("%s:field %d is out of range", mname, field_num);
return(DBENG_NO_SUCH_FIELD);
}
/* get field */
(void)ll_word(table->rec, field_out, field_num, DBENG_FM);
/* logman("%s:normal exit", mname); */
return(DBENG_OK);
}
int dbeng_get_subfield(struct dbeng_table *table, char *subfield_out,
int field_num, int subfield_num)
{
/* Obtain the 'subfield_num' sub-field in the field specified by
'field_num'. Function returns 'DBENG_OK' on success,
error code otherwise. Note that the caller must allocate
enough memory in 'subfield_out' to copy the field contents. */
char mname[] = "dbeng_get_subfield", *thefield;
int ret, nwords, fsize, nsubfields;
logman("%s:enter", mname);
if (table == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[table]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (subfield_out == (char *)NULL)
{
dbeng_io_code_log(mname, "null[subfield_out]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
subfield_out[0] = EOS;
if (field_num <= 0)
{
dbeng_io_code_log(mname, "out of range[field_num]",
DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (subfield_num <= 0)
{
dbeng_io_code_log(mname, "out of range[subfield_num]",
DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if ((ret = dbeng_is_active_rec(table)) != DBENG_OK)
{
dbeng_io_code_log(mname, "no current rec", ret);
return(ret);
}
if ((ret = dbeng_nsubfields(table, field_num, &nsubfields)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_nsubfields", ret);
return(ret);
}
if (subfield_num > nsubfields)
{
dbeng_io_code_log(mname, "out of range[subfield_num]",
DBENG_NO_SUCH_SUBFIELD);
return(DBENG_NO_SUCH_SUBFIELD);
}
/* attempt to get the size of the requested field */
if ((ret = dbeng_field_size(table, field_num, &fsize)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_field_size", ret);
return(ret);
}
if ((thefield = (char *)malloc(fsize + 1)) == (char *)NULL)
{
dbeng_io_code_log(mname, "alloc fail[thefield]", DBENG_MEMORY_FAIL);
return(DBENG_MEMORY_FAIL);
}
if ((ret = dbeng_get_field(table, thefield, field_num)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad ret from dbeng_get_field", ret);
free(thefield);
return(ret);
}
(void)ll_word(thefield, subfield_out, subfield_num, DBENG_SFM);
free(thefield);
logman("%s:normal exit", mname);
return(DBENG_OK);
}
int dbeng_get_subsubfield(struct dbeng_table *table, char *subsubfield_out,
int field_num, int subfield_num,
int subsubfield_num)
{
/* Obtain the 'subsubfield_num' sub-sub-field in the sub-field specified by
'subfield_num'. Function returns 'DBENG_OK' on success,
error code otherwise. Note that the caller must allocate
enough memory in 'subsubfield_out' to copy the field contents. */
char mname[] = "dbeng_get_subsubfield", *thesubfield;
int ret, nwords, sfsize, nsubsubfields;
logman("%s:enter", mname);
if (table == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[table]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (subsubfield_out == (char *)NULL)
{
dbeng_io_code_log(mname, "null[subsubfield_out]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
subsubfield_out[0] = EOS;
if (field_num <= 0)
{
dbeng_io_code_log(mname, "out of range[field_num]",
DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (subfield_num <= 0)
{
dbeng_io_code_log(mname, "out of range[subfield_num]",
DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (subsubfield_num <= 0)
{
dbeng_io_code_log(mname, "out of range[subsubfield_num]",
DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if ((ret = dbeng_is_active_rec(table)) != DBENG_OK)
{
dbeng_io_code_log(mname, "no current rec", ret);
return(ret);
}
if ((ret = dbeng_nsubsubfields(table, field_num, subfield_num,
&nsubsubfields)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_nsubsubfields", ret);
return(ret);
}
if (subsubfield_num > nsubsubfields)
{
dbeng_io_code_log(mname, "out of range[subsubfield_num]",
DBENG_NO_SUCH_SUBSUBFIELD);
return(DBENG_NO_SUCH_SUBSUBFIELD);
}
/* attempt to get the size of the requested sub-field */
if ((ret = dbeng_subfield_size(table, field_num, subfield_num,
&sfsize)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_subfield_size", ret);
return(ret);
}
if ((thesubfield = (char *)malloc(sfsize + 1)) == (char *)NULL)
{
dbeng_io_code_log(mname, "alloc fail[thesubfield]", DBENG_MEMORY_FAIL);
return(DBENG_MEMORY_FAIL);
}
if ((ret = dbeng_get_subfield(table, thesubfield, field_num,
subfield_num)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad ret from dbeng_get_subfield", ret);
free(thesubfield);
return(ret);
}
(void)ll_word(thesubfield, subsubfield_out, subsubfield_num, DBENG_SSFM);
free(thesubfield);
logman("%s:normal exit", mname);
return(DBENG_OK);
}
int dbeng_put_field(struct dbeng_table *table, char *new_data,
int field_num)
{
/* Store new data in a field and re-size record as
appropriate. Function returns 'DBENG_OK' upon success,
error code otherwise. */
char *old_rec, *new_rec;
char mname[] = "dbeng_put_field";
int new_rec_len, new_field_num;
int nwords;
int ret;
if (table == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[table]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (new_data == NULL)
{
dbeng_io_code_log(mname, "null[new_data]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if ((ret = dbeng_put_which_field(table, field_num, &new_field_num)) !=
DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_put_which_field", ret);
return(ret);
}
logman("%s:enter,tid=%d,d=%s,l=%d,f=%d,nf=%d", mname, table->tid,
new_data, strlen(new_data), field_num, new_field_num);
/* record can be empty */
/* if null record, create a stub */
if (table->rec == NULL)
{
if ((old_rec = malloc(25)) == NULL)
{
dbeng_io_code_log(mname, "alloc fail[old_rec]", DBENG_MEMORY_FAIL);
return(DBENG_MEMORY_FAIL);
}
old_rec[0] = EOS;
}
else
old_rec = initstring(table->rec); /* otherwise, copy the current rec */
nwords = ll_words(old_rec, DBENG_FM);
new_rec_len = strlen(old_rec) + strlen(new_data) + 1;
if (new_field_num > nwords)
new_rec_len += new_field_num - nwords;
/* make sure record is not too big */
if (DBENG_MAXRECFIELD > 0 && new_rec_len >= DBENG_MAXRECFIELD)
{
dbeng_io_code_log(mname, "rec too large", DBENG_RECORD_TOO_LARGE);
free(old_rec);
return(DBENG_RECORD_TOO_LARGE);
}
if ((new_rec = malloc(new_rec_len)) == NULL)
{
free(old_rec);
dbeng_io_code_log(mname, "alloc fail[new_rec]", DBENG_MEMORY_FAIL);
return(DBENG_MEMORY_FAIL);
}
if (!ll_wordput(old_rec, new_rec, new_data, new_field_num, DBENG_FM))
{
free(old_rec);
free(new_rec);
dbeng_io_code_log(mname, "bad ret[ll_wordput]",
DBENG_PUT_ERROR);
return(DBENG_PUT_ERROR);
}
ret = dbeng_rec_resize(table, strlen(new_rec));
if (ret != DBENG_OK)
{
free(old_rec);
free(new_rec);
dbeng_io_code_log(mname, "bad ret[rec_resize]", ret);
return(ret);
}
strcpy(table->rec, new_rec);
table->change_rec_flag = TRUE;
free(old_rec);
free(new_rec);
logman("%s:normal exit", mname);
return(DBENG_OK);
}
int dbeng_put_subfield(struct dbeng_table *table, char *new_data,
int field_num, int subfield_num)
{
/* Store new data in a sub-field and re-size record as
appropriate. Function returns 'DBENG_OK' upon success,
error code otherwise. */
char *old_field, *new_field;
char mname[] = "dbeng_put_subfield";
int field_len, new_field_len, new_fnum, new_sfnum;
int nwords;
int ret;
if (table == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[table]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (new_data == NULL)
{
dbeng_io_code_log(mname, "null[new_data]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if ((ret = dbeng_put_which_subfield(table, field_num, subfield_num,
&new_fnum, &new_sfnum)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_put_which_subfield", ret);
return(ret);
}
logman("%s:enter,tid=%d,d=%s,l=%d,f=%d,sf=%d,nf=%d,nsf=%d", mname,
table->tid, new_data, strlen(new_data), field_num,
subfield_num, new_fnum, new_sfnum);
/* if the field does not already exist, create it
unless there is no current record */
ret = dbeng_field_size(table, new_fnum, &field_len);
switch(ret)
{
case DBENG_OK:
break;
case DBENG_NO_RECORD:
field_len = 0;
break;
case DBENG_NO_SUCH_FIELD:
logman("%s:field[%d] does not exist,creating it",
mname, new_fnum);
if ((ret = dbeng_put_field(table, "", new_fnum)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_put_field", ret);
return(ret);
}
break;
default:
dbeng_io_code_log(mname, "bad rc from dbeng_field_size", ret);
return(ret);
};
/* it is possible that the field is empty, in which case, create a stub */
if (!field_len)
{
if ((old_field = (char *)malloc(25)) == (char *)NULL)
{
dbeng_io_code_log(mname, "alloc fail[old_field]1", DBENG_MEMORY_FAIL);
return(DBENG_MEMORY_FAIL);
}
old_field[0] = EOS;
}
else
{
if ((old_field = (char *)malloc(field_len + 1)) == (char *)NULL)
{
dbeng_io_code_log(mname, "alloc fail[old_field]2", DBENG_MEMORY_FAIL);
return(DBENG_MEMORY_FAIL);
}
if ((ret = dbeng_get_field(table, old_field, new_fnum)) != DBENG_OK)
{
free(old_field);
dbeng_io_code_log(mname, "bad rc from dbeng_get_field", ret);
return(ret);
}
}
nwords = ll_words(old_field, DBENG_SFM);
new_field_len = strlen(old_field) + strlen(new_data) + 1;
if (new_sfnum > nwords)
new_field_len += new_sfnum - nwords;
if ((new_field = malloc(new_field_len)) == NULL)
{
free(old_field);
dbeng_io_code_log(mname, "alloc fail[new_field]", DBENG_MEMORY_FAIL);
return(DBENG_MEMORY_FAIL);
}
if (!ll_wordput(old_field, new_field, new_data, new_sfnum, DBENG_SFM))
{
free(old_field);
free(new_field);
dbeng_io_code_log(mname, "bad ret[ll_wordput]",
DBENG_PUT_ERROR);
return(DBENG_PUT_ERROR);
}
free(old_field);
/* replace field */
if ((ret = dbeng_put_field(table, new_field, new_fnum)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad ret[dbeng_put_field]", ret);
free(new_field);
return(ret);
}
free(new_field);
logman("%s:normal exit", mname);
return(DBENG_OK);
}
int dbeng_put_subsubfield(struct dbeng_table *table, char *new_data,
int field_num, int subfield_num, int subsubfield_num)
{
/* Store new data in a sub-sub-field and re-size record as
appropriate. Function returns 'DBENG_OK' upon success,
error code otherwise. */
char *old_subfield, *new_subfield;
char mname[] = "dbeng_put_subsubfield";
int subfield_len, new_subfield_len, new_fnum, new_sfnum, new_ssfnum;
int nwords;
int ret;
if (table == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[table]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (new_data == NULL)
{
dbeng_io_code_log(mname, "null[new_data]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if ((ret = dbeng_put_which_subsubfield(table, field_num, subfield_num,
subsubfield_num, &new_fnum, &new_sfnum, &new_ssfnum)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_put_which_subsubfield", ret);
return(ret);
}
logman("%s:enter,tid=%d,d=%s,l=%d,f=%d,sf=%d,ssf=%d,nf=%d,nsf=%d,"
"nssf=%d", mname, table->tid, new_data, strlen(new_data),
field_num, subfield_num, subsubfield_num, new_fnum,
new_sfnum, new_ssfnum);
/* if the field and/or sub-field does not already exist, create it */
ret = dbeng_subfield_size(table, new_fnum, new_sfnum, &subfield_len);
switch(ret)
{
case DBENG_OK:
break;
case DBENG_NO_RECORD:
subfield_len = 0;
break;
case DBENG_NO_SUCH_FIELD:
case DBENG_NO_SUCH_SUBFIELD:
logman("%s:field or subfield does not exist,creating it",
mname);
if ((ret = dbeng_put_subfield(table, "", new_fnum, new_sfnum)) !=
DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_put_field", ret);
return(ret);
}
break;
default:
dbeng_io_code_log(mname, "bad rc from dbeng_subfield_size", ret);
return(ret);
};
/* it is possible that the field is empty, in which case, create a stub */
if (!subfield_len)
{
if ((old_subfield = (char *)malloc(25)) == (char *)NULL)
{
dbeng_io_code_log(mname, "alloc fail[old_subfield]1",
DBENG_MEMORY_FAIL);
return(DBENG_MEMORY_FAIL);
}
old_subfield[0] = EOS;
}
else
{
if ((old_subfield = (char *)malloc(subfield_len + 1)) == (char *)NULL)
{
dbeng_io_code_log(mname, "alloc fail[old_subfield]2",
DBENG_MEMORY_FAIL);
return(DBENG_MEMORY_FAIL);
}
if ((ret = dbeng_get_subfield(table, old_subfield, new_fnum,
new_sfnum)) != DBENG_OK)
{
free(old_subfield);
dbeng_io_code_log(mname, "bad rc from dbeng_get_subfield", ret);
return(ret);
}
}
nwords = ll_words(old_subfield, DBENG_SSFM);
new_subfield_len = strlen(old_subfield) + strlen(new_data) + 1;
if (new_ssfnum > nwords)
new_subfield_len += new_ssfnum - nwords;
if ((new_subfield = (char *)malloc(new_subfield_len)) == (char *)NULL)
{
free(old_subfield);
dbeng_io_code_log(mname, "alloc fail[new_subfield]", DBENG_MEMORY_FAIL);
return(DBENG_MEMORY_FAIL);
}
if (!ll_wordput(old_subfield, new_subfield, new_data, new_ssfnum,
DBENG_SSFM))
{
free(old_subfield);
free(new_subfield);
dbeng_io_code_log(mname, "bad ret[ll_wordput]",
DBENG_PUT_ERROR);
return(DBENG_PUT_ERROR);
}
free(old_subfield);
/* replace sub-field */
if ((ret = dbeng_put_subfield(table, new_subfield, new_fnum,
new_sfnum)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad ret[dbeng_put_subfield]", ret);
free(new_subfield);
return(ret);
}
free(new_subfield);
logman("%s:normal exit", mname);
return(DBENG_OK);
}
int dbeng_find(struct dbeng_table *ot, int cs_flag, const char *find_str,
int *field_num)
{
/* Locate 'find_str' within record data. All fields within
each record will be searched. Find will begin at current
record and continue until EOF or a record is found. Only whole
fields will match. String comparison is based on 'cs_flag' for
case sensitivity ('1' is case insensitivity, '0' is case sensitivity).
Function returns 'DBENG_OK' upon success, an
error code otherwise. If the find is successful, 'field_num' will
be loaded with field number that matched. */
char *field_data;
char mname[50];
int nwords, cmp_result;
int done;
int ret;
int i;
strcpy(mname, "dbeng_find");
if (ot == NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (cs_flag != TRUE && cs_flag != FALSE)
{
dbeng_io_code_log(mname, "must be 0|1[cs_flag]",
DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (find_str == NULL)
{
dbeng_io_code_log(mname, "null[find_str]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (field_num == NULL)
{
dbeng_io_code_log(mname, "null[field_num]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
logman("%s:enter,tid=%d,cs=%d,fs=%s,l=%d", mname, ot->tid, cs_flag,
find_str, strlen(find_str));
if (ot->enforce_change_rec_flag && ot->change_rec_flag)
{
dbeng_io_code_log(mname, "record changed", DBENG_RECORD_CHANGED);
return(DBENG_RECORD_CHANGED);
}
/* get a record if none is present (do not count unsaved rec in memory
if one is present) */
if (ot->record_number == 0L)
{
logman("%s:no current record,getting first", mname);
(void)dbeng_goto_top(ot);
ret = dbeng_get_recd(ot);
if (ret != DBENG_OK)
{
dbeng_io_code_log(mname, "bad ret first[get_recd]", ret);
return(ret);
}
}
done = FALSE;
*field_num = 0;
ot->change_rec_flag = FALSE;
while(!done)
{
if ((field_data = malloc(strlen(ot->rec) + 1)) == NULL)
{
dbeng_io_code_log(mname, "alloc fail[field_data]",
DBENG_MEMORY_FAIL);
return(DBENG_MEMORY_FAIL);
}
nwords = ll_words(ot->rec, DBENG_FM);
for(i = 1; i <= nwords; i++)
{
ret = dbeng_get_field(ot, field_data, i);
if (ret != DBENG_OK)
{
free(field_data);
dbeng_io_code_log(mname, "bad ret[get_field]", ret);
return(ret);
}
if ((ret = dbeng_compare_field(field_data, (char *)find_str, cs_flag,
&cmp_result)) != DBENG_OK)
{
free(field_data);
dbeng_io_code_log(mname, "bad ret[dbeng_compare_field]", ret);
return(ret);
}
if (!cmp_result)
{
*field_num = i;
free(field_data);
dbeng_io_code_log(mname, "match found,normal exit", DBENG_OK);
return(DBENG_OK);
}
}
free(field_data);
ret = dbeng_get_recd(ot);
if (ret != DBENG_OK)
done = TRUE;
}
dbeng_io_code_log(mname, "no match,normal exit", ret);
return(ret);
}
int dbeng_find_field(struct dbeng_table *ot, int cs_flag, const char *find_str,
int field_num)
{
/* Locate 'find_str' within the 'field_num' field of a record.
Each record will be searched. Find will begin at current
record and continue until EOF or a record is found. Only
whole fields will match. String comparison is obtained from
'cs_flag', for case sensitivity. Function returns 'DBENG_OK'
upon success, an error code otherwise. */
char *field_data;
char mname[50];
int nwords, cmp_result;
int done;
int ret;
strcpy(mname, "dbeng_find_field");
if (ot == NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (cs_flag != TRUE && cs_flag != FALSE)
{
dbeng_io_code_log(mname, "must be 0|1[cs_flag]",
DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (find_str == NULL)
{
dbeng_io_code_log(mname, "null[find_str]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (field_num <= 0)
{
dbeng_io_code_log(mname, "illegal[field_num]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
logman("%s:enter,tid=%d,cs=%d,fs=%s,l=%d,fn=%d", mname,
ot->tid, cs_flag, find_str, strlen(find_str), field_num);
if (ot->enforce_change_rec_flag && ot->change_rec_flag)
{
dbeng_io_code_log(mname, "record changed", DBENG_RECORD_CHANGED);
return(DBENG_RECORD_CHANGED);
}
/* get a record if none is present (do not count unsaved rec in memory
if one is present) */
if (ot->record_number == 0L)
{
logman("%s:no current record,getting first", mname);
(void)dbeng_goto_top(ot);
ret = dbeng_get_recd(ot);
if (ret != DBENG_OK)
{
dbeng_io_code_log(mname, "bad ret first[get_recd]", ret);
return(ret);
}
}
done = FALSE;
ot->change_rec_flag = FALSE;
while(!done)
{
if ((field_data = malloc(strlen(ot->rec) + 1)) == NULL)
{
dbeng_io_code_log(mname, "alloc fail[field_data]",
DBENG_MEMORY_FAIL);
return(DBENG_MEMORY_FAIL);
}
nwords = ll_words(ot->rec, DBENG_FM);
if (nwords >= field_num)
{
ret = dbeng_get_field(ot, field_data, field_num);
if (ret != DBENG_OK)
{
free(field_data);
dbeng_io_code_log(mname, "bad ret[get_field]", ret);
return(ret);
}
if ((ret = dbeng_compare_field(field_data, (char *)find_str, cs_flag,
&cmp_result)) != DBENG_OK)
{
free(field_data);
dbeng_io_code_log(mname, "bad ret[dbeng_compare_field", ret);
return(ret);
}
if (!cmp_result)
{
free(field_data);
dbeng_io_code_log(mname, "match found,normal exit", DBENG_OK);
return(DBENG_OK);
}
}
free(field_data);
ret = dbeng_get_recd(ot);
if (ret != DBENG_OK)
done = TRUE;
}
dbeng_io_code_log(mname, "no match,normal exit", ret);
return(ret);
}
int dbeng_find_part(struct dbeng_table *ot, int cs_flag, const char *find_str,
int *field_num)
{
/* Locate 'find_str' within record data. All fields within
each record will be searched. Find will begin at current
record and continue until EOF or a record is found. Any part
of a field will match. String comparison is based on 'cs_flag'
for case sensitivity. Function returns 'DBENG_OK' upon success,
an error code otherwise. If the find is successful, 'field_num' will
be loaded with field number that matched. */
char *field_data;
char mname[50];
int nwords;
int done;
int ret;
int process;
int field_len;
int len_find_str;
int i, j;
strcpy(mname, "dbeng_find_part");
if (ot == NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (cs_flag != TRUE && cs_flag != FALSE)
{
dbeng_io_code_log(mname, "must be 0|1[cs_flag]",
DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (find_str == NULL)
{
dbeng_io_code_log(mname, "null[find_str]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (field_num == NULL)
{
dbeng_io_code_log(mname, "null[field_num]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
logman("%s:enter,tid=%d,cs=%d,fs=%s,l=%d", mname, ot->tid, cs_flag,
find_str, strlen(find_str));
if (ot->enforce_change_rec_flag && ot->change_rec_flag)
{
dbeng_io_code_log(mname, "record changed", DBENG_RECORD_CHANGED);
return(DBENG_RECORD_CHANGED);
}
/* get a record if none is present (do not count unsaved rec in memory
if one is present) */
if (ot->record_number == 0L)
{
(void)dbeng_goto_top(ot);
ret = dbeng_get_recd(ot);
if (ret != DBENG_OK)
{
dbeng_io_code_log(mname, "bad ret first[get_recd]", ret);
return(ret);
}
}
done = FALSE;
len_find_str = strlen(find_str);
*field_num = 0;
ot->change_rec_flag = FALSE;
while(!done)
{
if ((field_data = malloc(strlen(ot->rec) + 1)) == NULL)
{
dbeng_io_code_log(mname, "alloc fail[field_data]",
DBENG_MEMORY_FAIL);
return(DBENG_MEMORY_FAIL);
}
nwords = ll_words(ot->rec, DBENG_FM);
for(i = 1; i <= nwords; i++)
{
ret = dbeng_get_field(ot, field_data, i);
if (ret != DBENG_OK)
{
free(field_data);
dbeng_io_code_log(mname, "bad ret[get_field]", ret);
return(ret);
}
field_len = strlen(field_data);
process = TRUE;
/* do not compare if length of field is less than
length of search string */
if (field_len < len_find_str)
process = FALSE;
if (process)
{
for(j = 0; j < field_len; j++)
{
if (strlen(&field_data[j]) < len_find_str)
break;
if (cs_flag)
ret = strnicmp(&field_data[j], (char *)find_str, len_find_str);
else
ret = strncmp(&field_data[j], find_str, len_find_str);
if (!ret)
{
*field_num = i;
free(field_data);
dbeng_io_code_log(mname, "match found,normal exit",
DBENG_OK);
return(DBENG_OK);
}
}
}
}
free(field_data);
ret = dbeng_get_recd(ot);
if (ret != DBENG_OK)
done = TRUE;
}
dbeng_io_code_log(mname, "no match,normal exit", ret);
return(ret);
}
int dbeng_find_field_part(struct dbeng_table *ot, int cs_flag,
const char *find_str, int field_num)
{
/* Locate 'find_str' within the 'field_num' field of a record.
Each record will be searched. Find will begin at current
record and continue until EOF or a record is found. Any part
of the field will match. String comparison is obtained from
'cs_flag', for case sensitivity. Function returns 'DBENG_OK'
upon success, an error code otherwise. */
char *field_data;
char mname[50];
int field_len;
int len_find_str;
int process;
int nwords;
int done;
int ret;
int i;
strcpy(mname, "dbeng_find_field_part");
if (ot == NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (cs_flag != TRUE && cs_flag != FALSE)
{
dbeng_io_code_log(mname, "must be 0|1[cs_flag]",
DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (find_str == NULL)
{
dbeng_io_code_log(mname, "null[find_str]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (field_num <= 0)
{
dbeng_io_code_log(mname, "illegal[field_num]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
logman("%s:enter,tid=%d,cs=%d,fs=%s,l=%d,fn=%d", mname,
ot->tid, cs_flag, find_str, strlen(find_str), field_num);
if (ot->enforce_change_rec_flag && ot->change_rec_flag)
{
dbeng_io_code_log(mname, "record changed", DBENG_RECORD_CHANGED);
return(DBENG_RECORD_CHANGED);
}
/* get a record if none is present (do not count unsaved rec in memory
if one is present) */
if (ot->record_number == 0L)
{
(void)dbeng_goto_top(ot);
ret = dbeng_get_recd(ot);
if (ret != DBENG_OK)
{
dbeng_io_code_log(mname, "bad ret first[get_recd]", ret);
return(ret);
}
}
done = FALSE;
len_find_str = strlen(find_str);
ot->change_rec_flag = FALSE;
while(!done)
{
if ((field_data = malloc(strlen(ot->rec) + 1)) == NULL)
{
dbeng_io_code_log(mname, "alloc fail[field_data]",
DBENG_MEMORY_FAIL);
return(DBENG_MEMORY_FAIL);
}
process = TRUE;
nwords = ll_words(ot->rec, DBENG_FM);
if (field_num > nwords)
process = FALSE;
if (process)
{
ret = dbeng_get_field(ot, field_data, field_num);
if (ret != DBENG_OK)
{
free(field_data);
dbeng_io_code_log(mname, "bad ret[get_field]", ret);
return(ret);
}
field_len = strlen(field_data);
if (field_len < len_find_str)
process = FALSE;
}
if (process)
{
for(i = 0; i < field_len; i++)
{
if (strlen(&field_data[i]) < len_find_str)
break;
if (cs_flag)
ret = strnicmp(&field_data[i], (char *)find_str, len_find_str);
else
ret = strncmp(&field_data[i], find_str, len_find_str);
if (!ret)
{
free(field_data);
dbeng_io_code_log(mname, "match found,normal exit", DBENG_OK);
return(DBENG_OK);
}
}
}
free(field_data);
ret = dbeng_get_recd(ot);
if (ret != DBENG_OK)
done = TRUE;
}
dbeng_io_code_log(mname, "no match,normal exit", ret);
return(ret);
}
int dbeng_nfields(struct dbeng_table *ot, int *nfields)
{
/* Count the number of fields in the current record. Number
of fields is loaded into 'nfields' upon success. Function
returns 'DBENG_OK' upon success, an error code otherwise. */
char mname[50];
int ret;
strcpy(mname, "dbeng_nfields");
logman("%s:enter", mname);
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (nfields == (int *)NULL)
{
dbeng_io_code_log(mname, "null[nfields]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
*nfields = 0;
if ((ret = dbeng_is_active_rec(ot)) != DBENG_OK)
{
dbeng_io_code_log(mname, "no current rec", ret);
return(ret);
}
*nfields = ll_words(ot->rec, DBENG_FM);
logman("%s:normal exit", mname);
return(DBENG_OK);
}
int dbeng_nsubfields(struct dbeng_table *ot, int fieldno, int *nsubfields)
{
/* Count the number of sub-fields in the 'fieldno' field. Number
of sub-fields is loaded into 'nsubfields' upon success. Function
returns 'DBENG_OK' upon success, an error code otherwise. */
char mname[] = "dbeng_nsubfields", *thefield;
int ret, fsize;
logman("%s:enter", mname);
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (fieldno <= 0)
{
dbeng_io_code_log(mname, "invalid[fieldno]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (nsubfields == (int *)NULL)
{
dbeng_io_code_log(mname, "null[nsubfields]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
*nsubfields = 0;
if ((ret = dbeng_is_active_rec(ot)) != DBENG_OK)
{
dbeng_io_code_log(mname, "no current rec", ret);
return(ret);
}
/* attempt to get the size of the requested field */
if ((ret = dbeng_field_size(ot, fieldno, &fsize)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_field_size", ret);
return(ret);
}
if ((thefield = (char *)malloc(fsize + 1)) == (char *)NULL)
{
dbeng_io_code_log(mname, "alloc fail[thefield]", DBENG_MEMORY_FAIL);
return(DBENG_MEMORY_FAIL);
}
if ((ret = dbeng_get_field(ot, thefield, fieldno)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad ret from dbeng_get_field", ret);
free(thefield);
return(ret);
}
*nsubfields = ll_words(thefield, DBENG_SFM);
free(thefield);
logman("%s:normal exit:nsubfields=%d", mname, *nsubfields);
return(DBENG_OK);
}
int dbeng_nsubsubfields(struct dbeng_table *ot, int fieldno,
int sfieldno, int *nsubsubfields)
{
/* Count the number of sub-sub-fields in the 'sfieldno' sub-field. Number
of sub-sub-fields is loaded into 'nsubsubfields' upon success. Function
returns 'DBENG_OK' upon success, an error code otherwise. */
char mname[] = "dbeng_nsubsubfields", *thesfield;
int ret, sfsize;
logman("%s:enter", mname);
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (fieldno <= 0)
{
dbeng_io_code_log(mname, "invalid[fieldno]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (sfieldno <= 0)
{
dbeng_io_code_log(mname, "invalid[sfieldno]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (nsubsubfields == (int *)NULL)
{
dbeng_io_code_log(mname, "null[nsubsubfields]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
*nsubsubfields = 0;
if ((ret = dbeng_is_active_rec(ot)) != DBENG_OK)
{
dbeng_io_code_log(mname, "no current rec", ret);
return(ret);
}
/* attempt to get the size of the requested sub-field */
if ((ret = dbeng_subfield_size(ot, fieldno, sfieldno, &sfsize)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_subfield_size", ret);
return(ret);
}
if ((thesfield = (char *)malloc(sfsize + 1)) == (char *)NULL)
{
dbeng_io_code_log(mname, "alloc fail[thesfield]", DBENG_MEMORY_FAIL);
return(DBENG_MEMORY_FAIL);
}
if ((ret = dbeng_get_subfield(ot, thesfield, fieldno, sfieldno)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad ret from dbeng_get_subfield", ret);
free(thesfield);
return(ret);
}
*nsubsubfields = ll_words(thesfield, DBENG_SSFM);
free(thesfield);
logman("%s:normal exit:nsubsubfields=%d", mname, *nsubsubfields);
return(DBENG_OK);
}
int dbeng_count_rec(struct dbeng_table *table, long *active_count,
long *deleted_count)
{
/* Physically count the number active and deleted records in 'table'
and return upon success. Function returns 'DBENG_OK'
upon success, an error code otherwise. */
char mname[] = "dbeng_count_rec";
long active_num = 0L;
long deleted_num = 0L;
int done = FALSE;
int ret, delete_flag;
if (table == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[table]", DBENG_INVALID_FILE_NAME);
return(DBENG_INVALID_FILE_NAME);
}
if (active_count == (long *)NULL)
{
dbeng_io_code_log(mname, "null[active_count]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (deleted_count == (long *)NULL)
{
dbeng_io_code_log(mname, "null[deleted_count]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
*active_count = *deleted_count = 0L;
logman("%s:enter:tid=%d", mname, table->tid);
if (table->enforce_change_rec_flag && table->change_rec_flag)
{
dbeng_io_code_log(mname, "record changed", DBENG_RECORD_CHANGED);
return(DBENG_RECORD_CHANGED);
}
/* get current value of table 'delete_flag' */
(void)dbeng_delete_flag(table, &delete_flag);
/* set delete flag */
(void)dbeng_set_delete_flag(table, TRUE);
ret = dbeng_goto_top(table);
if (ret != DBENG_OK)
{
dbeng_io_code_log(mname, "error going top", ret);
return(ret);
}
while(!done)
{
ret = dbeng_get_recd(table);
if (ret == DBENG_EOF)
done = TRUE;
else
if (ret != DBENG_OK)
return(ret);
else
table->record_status ? active_num++ : deleted_num++;
}
/* set flag back to original value */
(void)dbeng_set_delete_flag(table, delete_flag);
logman("%s:normal exit:%ld active,%ld deleted records counted",
mname, active_num, deleted_num);
*active_count = active_num;
*deleted_count = deleted_num;
return(DBENG_OK);
}
int dbeng_rec_count(struct dbeng_table *ot, long *active_count,
long *deleted_count)
{
/* Obtain the current active and deleted record counts. Function returns the
record count values and 'DBENG_OK' upon success, an error
code otherwise. */
char mname[75];
strcpy(mname, "dbeng_record_count");
logman("%s:enter", mname);
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (active_count == (long *)NULL)
{
dbeng_io_code_log(mname, "null[active_count]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (deleted_count == (long *)NULL)
{
dbeng_io_code_log(mname, "null[deleted_count]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
*active_count = ot->active_record_count;
*deleted_count = ot->deleted_record_count;
logman("%s:normal exit[ok]", mname);
return(DBENG_OK);
}
int dbeng_goto_record(struct dbeng_table *table, long rec_num)
{
/* Goto a specific record in the file. */
char mname[50];
long i;
int ret;
strcpy(mname, "dbeng_goto_record");
if (table == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[table]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (rec_num <= 0L)
{
dbeng_io_code_log(mname, "out of range[rec_num]",
DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
logman("%s:enter:rn=%ld", mname, rec_num);
if (table->enforce_change_rec_flag && table->change_rec_flag)
{
dbeng_io_code_log(mname, "record changed", DBENG_RECORD_CHANGED);
return(DBENG_RECORD_CHANGED);
}
ret = dbeng_goto_top(table);
if (ret != DBENG_OK)
{
dbeng_io_code_log(mname, "error going top", ret);
return(ret);
}
ret = dbeng_get_recd(table);
if (ret != DBENG_OK)
{
dbeng_io_code_log(mname, "bad ret first[get_recd]", ret);
return(ret);
}
for(i = 1L; i < rec_num; i++)
if (dbeng_get_recd(table) == DBENG_EOF && i < rec_num)
{
dbeng_io_code_log(mname, "exit with eof", DBENG_EOF);
return(DBENG_EOF);
}
logman("%s:normal exit", mname);
return(DBENG_OK);
}
int dbeng_get_recd(struct dbeng_table *ot)
{
/* Obtain the next record in the file. */
char mname[] = "dbeng_get_recd";
char ferror[128], rec_status;
long file_pos;
int bytes_read, len;
int done = FALSE, process;
int ret;
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (ot->enforce_change_rec_flag && ot->change_rec_flag)
{
dbeng_io_code_log(mname, "record changed", DBENG_RECORD_CHANGED);
return(DBENG_RECORD_CHANGED);
}
/* loop to get record */
while(!done)
{
file_pos = ftell(ot->handle);
/* logman("%s:fp=%ld,op=%ld,cp=%ld", mname, file_pos,
ot->orig_position, ot->current_position); */
/* read and verify record header */
if ((ret = dbeng_record_header(ot, &len, &rec_status)) != DBENG_OK)
{
if (ret == DBENG_FILE_DATA_ERROR)
{
sprintf(ferror, "%s:error in header of "
"record %ld,tid=%d", mname,
ot->record_number + 1L, ot->tid);
dbeng_ferror(ferror);
}
/* goto top of table on any error code */
(void)dbeng_goto_top(ot);
return(ret);
}
/* store starting position of this record */
ot->orig_position = file_pos;
if (DBENG_MAXRECFIELD > 0 && len >= DBENG_MAXRECFIELD)
{
sprintf(ferror, "%s:error:record %ld too large(%d)\n"
"must be no greater than %d,table=%s",
mname, ot->record_number, len, DBENG_MAXRECFIELD,
ot->name);
dbeng_ferror(ferror);
return(DBENG_RECORD_TOO_LARGE);
}
/* get status and process only if active record considering the
'process_deleted' flag */
process = (rec_status == 'A') ? TRUE : FALSE;
ot->record_status = process;
if (!process)
if (rec_status == 'D' && ot->process_deleted)
process = TRUE;
/* if marked for deletion, skip */
if (!process && rec_status == 'D')
{
ret = dbeng_rec_resize(ot, len);
if (ret != DBENG_OK)
return(ret);
bytes_read = fread(ot->rec, 1, len, ot->handle);
if (bytes_read < len)
{
sprintf(ferror, "%s:unexpected end of file reading record %ld"
" of table %s", mname, ot->record_number + 1L,
ot->name);
dbeng_ferror(ferror);
return(DBENG_FILE_DATA_ERROR);
}
/* error if record mark is not the last byte */
if ((unsigned char)ot->rec[len - 1] != DBENG_RM)
{
sprintf(ferror, "%s:error, no record mark "
"on record %ld,table=%s", mname, ot->record_number + 1L,
ot->name);
dbeng_ferror(ferror);
return(DBENG_FILE_DATA_ERROR);
}
}
if (process)
{
ret = dbeng_rec_resize(ot, len);
if (ret != DBENG_OK)
return(ret);
done = TRUE;
bytes_read = fread(ot->rec, 1, len, ot->handle);
if (bytes_read < len)
{
sprintf(ferror, "%s:unexpected end of file reading record %ld"
",table=%s", mname, ot->record_number + 1L,
ot->name);
dbeng_ferror(ferror);
return(DBENG_FILE_DATA_ERROR);
}
if ((unsigned char)ot->rec[len - 1] != DBENG_RM)
{
sprintf(ferror, "%s:error, no record mark on record %ld,"
"table=%s", mname, ot->record_number + 1L,
ot->name);
dbeng_ferror(ferror);
return(DBENG_FILE_DATA_ERROR);
}
ot->rec[len - 1] = EOS; /* remove record separator */
ot->current_position = ftell(ot->handle);
// logman("%s:cp=%ld", mname, ot->current_position);
ot->record_number++;
}
}
return(DBENG_OK);
}
int dbeng_rec_resize(struct dbeng_table *ot, const int new_size)
{
/* Resize the table record to 'new_size'. Function returns
'DBENG_OK' upon success, an error code otherwise. */
char mname[50];
strcpy(mname, "dbeng_rec_resize");
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (new_size <= 0)
{
dbeng_io_code_log(mname, "out of range[new_size]",
DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
/* delete current record, if one present */
if (dbeng_is_active_rec(ot) == DBENG_OK)
free(ot->rec);
/* allocate new record */
if ((ot->rec = malloc(new_size + 1)) == (char *)NULL)
return(DBENG_MEMORY_FAIL);
return(DBENG_OK);
}
int dbeng_rec_size(struct dbeng_table *ot, int *rec_size)
{
/* Get the current record size or length. Upon success,
'rec_size' will be loaded with the size and function
will return 'DBENG_OK'. Function will return an
error code (and 'rec_size' will be set to zero) upon
failure. */
char mname[50];
int ret;
strcpy(mname, "dbeng_rec_size");
logman("%s:enter", mname);
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (rec_size == NULL)
{
dbeng_io_code_log(mname, "null[rec_size]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
*rec_size = 0;
if ((ret = dbeng_is_active_rec(ot)) != DBENG_OK)
{
dbeng_io_code_log(mname, "no current rec", ret);
return(ret);
}
*rec_size = strlen(ot->rec);
logman("%s:normal exit", mname);
return(DBENG_OK);
}
int dbeng_field_size(struct dbeng_table *ot, const int field_num,
int *field_size)
{
/* Get the size or length of field 'field_num' in the current
record. Variable 'field_size' will be loaded with the
field size upon success. Function returns 'DBENG_OK'
upon success, an error code otherwise. */
char mname[] = "dbeng_field_size";
int ret;
int nfields;
logman("%s:enter:fn=%d", mname, field_num);
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (field_num <= 0)
{
dbeng_io_code_log(mname, "out of range[field_num]",
DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (field_size == NULL)
{
dbeng_io_code_log(mname, "null[field_size]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
*field_size = 0;
if ((ret = dbeng_is_active_rec(ot)) != DBENG_OK)
{
dbeng_io_code_log(mname, "no current rec", ret);
return(ret);
}
if ((ret = dbeng_nfields(ot, &nfields)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad ret[nfields]", ret);
return(ret);
}
if (field_num > nfields)
{
dbeng_io_code_log(mname, "field out of range", DBENG_NO_SUCH_FIELD);
return(DBENG_NO_SUCH_FIELD);
}
*field_size = ll_wordlen(ot->rec, field_num, DBENG_FM);
logman("%s:normal exit", mname);
return(DBENG_OK);
}
int dbeng_subfield_size(struct dbeng_table *ot, int field_num,
int subfield_num, int *subfield_size)
{
/* Get the size or length of sub-field 'subfield_num'
within the field 'field_num' in the current
record. Variable 'subfield_size' will be loaded with the
sub-field size upon success. Function returns 'DBENG_OK'
upon success, an error code otherwise. */
char mname[] = "dbeng_subfield_size", *thefield;
int ret, nsubfields, fsize;
logman("%s:enter", mname);
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (field_num <= 0)
{
dbeng_io_code_log(mname, "out of range[field_num]",
DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (subfield_num <= 0)
{
dbeng_io_code_log(mname, "out of range[subfield_num]",
DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (subfield_size == (int *)NULL)
{
dbeng_io_code_log(mname, "null[subfield_size]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
*subfield_size = 0;
if ((ret = dbeng_is_active_rec(ot)) != DBENG_OK)
{
dbeng_io_code_log(mname, "no current rec", ret);
return(ret);
}
if ((ret = dbeng_nsubfields(ot, field_num, &nsubfields)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_nsubfields", ret);
return(ret);
}
if (subfield_num > nsubfields)
{
dbeng_io_code_log(mname, "out of range[subfield_num]",
DBENG_NO_SUCH_SUBFIELD);
return(DBENG_NO_SUCH_SUBFIELD);
}
/* attempt to get the size of the requested field */
if ((ret = dbeng_field_size(ot, field_num, &fsize)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_field_size", ret);
return(ret);
}
if ((thefield = (char *)malloc(fsize + 1)) == (char *)NULL)
{
dbeng_io_code_log(mname, "alloc fail[thefield]", DBENG_MEMORY_FAIL);
return(DBENG_MEMORY_FAIL);
}
if ((ret = dbeng_get_field(ot, thefield, field_num)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad ret from dbeng_get_field", ret);
free(thefield);
return(ret);
}
*subfield_size = ll_wordlen(thefield, subfield_num, DBENG_SFM);
free(thefield);
logman("%s:normal exit", mname);
return(DBENG_OK);
}
int dbeng_subsubfield_size(struct dbeng_table *ot, int field_num,
int subfield_num, int subsubfield_num,
int *subsubfield_size)
{
/* Get the size or length of sub-sub-field 'subsubfield_num'
within the sub-field 'subfield_num' in the current
record. Variable 'subsubfield_size' will be loaded with the
sub-sub-field size upon success. Function returns 'DBENG_OK'
upon success, an error code otherwise. */
char mname[] = "dbeng_subsubfield_size", *thesubfield;
int ret, nsubsubfields, sfsize;
logman("%s:enter", mname);
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (field_num <= 0)
{
dbeng_io_code_log(mname, "out of range[field_num]",
DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (subfield_num <= 0)
{
dbeng_io_code_log(mname, "out of range[subfield_num]",
DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (subsubfield_num <= 0)
{
dbeng_io_code_log(mname, "out of range[subsubfield_num]",
DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (subsubfield_size == (int *)NULL)
{
dbeng_io_code_log(mname, "null[subsubfield_size]",
DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
*subsubfield_size = 0;
if ((ret = dbeng_is_active_rec(ot)) != DBENG_OK)
{
dbeng_io_code_log(mname, "no current rec", ret);
return(ret);
}
if ((ret = dbeng_nsubsubfields(ot, field_num, subfield_num,
&nsubsubfields)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_nsubsubfields", ret);
return(ret);
}
if (subsubfield_num > nsubsubfields)
{
dbeng_io_code_log(mname, "out of range[subsubfield_num]",
DBENG_NO_SUCH_SUBSUBFIELD);
return(DBENG_NO_SUCH_SUBSUBFIELD);
}
/* attempt to get the size of the requested sub-field */
if ((ret = dbeng_subfield_size(ot, field_num, subfield_num,
&sfsize)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_subfield_size", ret);
return(ret);
}
if ((thesubfield = (char *)malloc(sfsize + 1)) == (char *)NULL)
{
dbeng_io_code_log(mname, "alloc fail[thesubfield]", DBENG_MEMORY_FAIL);
return(DBENG_MEMORY_FAIL);
}
if ((ret = dbeng_get_subfield(ot, thesubfield, field_num,
subfield_num)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad ret from dbeng_get_subfield", ret);
free(thesubfield);
return(ret);
}
*subsubfield_size = ll_wordlen(thesubfield, subsubfield_num, DBENG_SSFM);
free(thesubfield);
logman("%s:normal exit", mname);
return(DBENG_OK);
}
int dbeng_rec_num(struct dbeng_table *ot, long *rec_num)
{
/* Obtain the current record number. Function returns the
current record number in 'rec_num' and 'DBENG_OK' upon
success, an error code otherwise. */
char mname[50];
strcpy(mname, "dbeng_rec_num");
logman("%s:enter", mname);
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (rec_num == NULL)
{
dbeng_io_code_log(mname, "null[rec_num]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
*rec_num = 0L;
if (ot->record_number <= 0L)
{
dbeng_io_code_log(mname, "no current rec", DBENG_NO_RECORD);
return(DBENG_NO_RECORD);
}
*rec_num = ot->record_number;
dbeng_io_code_log(mname, "normal exit", DBENG_OK);
return(DBENG_OK);
}
int dbeng_pos(struct dbeng_table *ot, long *pos)
{
/* Obtain the current file position. Function returns the
position of the start of the current record in 'pos' and
'DBENG_OK' upon success, an error code otherwise. */
char mname[50];
strcpy(mname, "dbeng_pos");
logman("%s:enter", mname);
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (pos == NULL)
{
dbeng_io_code_log(mname, "null[pos]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
*pos = 0L;
if (ot->orig_position < 0L)
{
dbeng_io_code_log(mname, "no current rec", DBENG_NO_RECORD);
return(DBENG_NO_RECORD);
}
*pos = ot->orig_position;
dbeng_io_code_log(mname, "normal exit", DBENG_OK);
return(DBENG_OK);
}
int dbeng_set_pos(struct dbeng_table *ot, long pos)
{
/* Set the current file position. 'dbeng' structure
member 'orig_position' will be updated along with
moving the file pointer. BE VERY CAREFUL. You
be sure there is a record at the specified
'pos'. Current record contents are
not changed. Only the file pointer position is moved.
A record is not read into the buffer. Function
returns 'DBENG_OK' upon success, an error code
otherwise. */
char mname[] = "dbeng_set_pos";
logman("%s:enter", mname);
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (pos < 0L)
{
dbeng_io_code_log(mname, "illegal[pos]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (ot->enforce_change_rec_flag && ot->change_rec_flag)
{
dbeng_io_code_log(mname, "record changed", DBENG_RECORD_CHANGED);
return(DBENG_RECORD_CHANGED);
}
ot->orig_position = ot->current_position = pos;
fseek(ot->handle, ot->orig_position, 0);
dbeng_io_code_log(mname, "normal exit", DBENG_OK);
return(DBENG_OK);
}
int dbeng_change_rec_flag(struct dbeng_table *ot, int *flag)
{
/* Obtain the current 'change_rec_flag' value. Function returns the
value of the flag in 'flag' and 'DBENG_OK' upon success, an error
code otherwise. */
char mname[50];
int ret;
strcpy(mname, "dbeng_change_rec_flag");
logman("%s:enter", mname);
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (flag == NULL)
{
dbeng_io_code_log(mname, "null[flag]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
*flag = 0;
if ((ret = dbeng_is_active_rec(ot)) != DBENG_OK)
{
dbeng_io_code_log(mname, "no current rec", ret);
return(ret);
}
*flag = ot->change_rec_flag;
dbeng_io_code_log(mname, "normal exit", DBENG_OK);
return(DBENG_OK);
}
int dbeng_set_change_rec_flag(struct dbeng_table *ot, int flag)
{
/* Set a new 'change_rec_flag' value. Function returns 'DBENG_OK' upon
success, an error code otherwise. Flag must be either 'TRUE' or
'FALSE'. */
char mname[50];
int ret;
strcpy(mname, "dbeng_set_change_rec_flag");
logman("%s:enter", mname);
if (ot == NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (flag != TRUE && flag != FALSE)
{
dbeng_io_code_log(mname, "invalid[flag]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if ((ret = dbeng_is_active_rec(ot)) != DBENG_OK)
{
dbeng_io_code_log(mname, "no current rec", ret);
return(ret);
}
ot->change_rec_flag = flag;
dbeng_io_code_log(mname, "normal exit", DBENG_OK);
return(DBENG_OK);
}
int dbeng_delete_flag(struct dbeng_table *ot, int *flag)
{
/* Obtain the current 'process_deleted' value. Function returns the
value of the flag in 'flag' and 'DBENG_OK' upon success, an error
code otherwise. */
char mname[50];
strcpy(mname, "dbeng_delete_flag");
logman("%s:enter", mname);
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (flag == NULL)
{
dbeng_io_code_log(mname, "null[flag]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
*flag = ot->process_deleted;
dbeng_io_code_log(mname, "normal exit", DBENG_OK);
return(DBENG_OK);
}
int dbeng_set_delete_flag(struct dbeng_table *ot, int flag)
{
/* Set a new 'process_deleted' value. Function returns 'DBENG_OK' upon
success, an error code otherwise. Flag must be either 'TRUE' or
'FALSE'. */
char mname[50];
strcpy(mname, "dbeng_set_delete_flag");
logman("%s:enter", mname);
if (ot == NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (flag != TRUE && flag != FALSE)
{
dbeng_io_code_log(mname, "invalid[flag]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
ot->process_deleted = flag;
dbeng_io_code_log(mname, "normal exit", DBENG_OK);
return(DBENG_OK);
}
int dbeng_enf_change_rec_flag(struct dbeng_table *ot, int *flag)
{
/* Obtain the current 'enforce_change_rec_flag' value. Function
returns the value of the flag in 'flag' and 'DBENG_OK' upon
success, an error code otherwise. */
char mname[50];
strcpy(mname, "dbeng_enf_change_rec_flag");
logman("%s:enter", mname);
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (flag == NULL)
{
dbeng_io_code_log(mname, "null[flag]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
*flag = ot->enforce_change_rec_flag;
dbeng_io_code_log(mname, "normal exit", DBENG_OK);
return(DBENG_OK);
}
int dbeng_set_enf_change_rec_flag(struct dbeng_table *ot, int flag)
{
/* Set a new 'enforce_change_rec_flag' value. Function returns
'DBENG_OK' upon success, an error code otherwise. 'Flag' must
be either 'TRUE' or 'FALSE'. */
char mname[50];
strcpy(mname, "dbeng_set_enf_change_rec_flag");
logman("%s:enter", mname);
if (ot == NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (flag != TRUE && flag != FALSE)
{
dbeng_io_code_log(mname, "invalid[flag]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
ot->enforce_change_rec_flag = flag;
dbeng_io_code_log(mname, "normal exit", DBENG_OK);
return(DBENG_OK);
}
int dbeng_autopack(struct dbeng_table *ot, int *pvalue)
{
/* Obtain the current 'autopack' value. Function returns the
value in 'pvalue' and 'DBENG_OK' upon success, an error
code otherwise. */
char mname[] = "dbeng_autopack";
int ret;
logman("%s:enter", mname);
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (pvalue == (int *)NULL)
{
dbeng_io_code_log(mname, "null[pvalue]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
*pvalue = ot->autopack;
dbeng_io_code_log(mname, "normal exit", DBENG_OK);
return(DBENG_OK);
}
int dbeng_set_autopack(struct dbeng_table *ot, int pvalue)
{
/* Set a new 'autopack' value. Function returns 'DBENG_OK' upon
success, an error code otherwise. */
char mname[] = "dbeng_set_autopack";
int ret;
logman("%s:enter", mname);
if (ot == NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (pvalue < 0)
{
dbeng_io_code_log(mname, "out of range[pvalue]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
ot->autopack = pvalue;
dbeng_io_code_log(mname, "normal exit", DBENG_OK);
return(DBENG_OK);
}
int dbeng_is_table_locked(struct dbeng_table *ot, int *flag)
{
/* Obtain the current 'is_table_locked' value. Function
returns the value of the flag in 'flag' and 'DBENG_OK' upon
success, an error code otherwise. */
char mname[25];
strcpy(mname, "dbeng_is_table_locked");
logman("%s:enter", mname);
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (flag == NULL)
{
dbeng_io_code_log(mname, "null[flag]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
*flag = ot->is_table_locked;
dbeng_io_code_log(mname, "normal exit", DBENG_OK);
return(DBENG_OK);
}
int dbeng_set_is_table_locked(struct dbeng_table *ot, int flag)
{
/* Set a new 'is_table_locked' value. Function returns
'DBENG_OK' upon success, an error code otherwise. 'Flag' must
be either 'TRUE' or 'FALSE'. */
char mname[30];
int ret;
strcpy(mname, "dbeng_set_is_table_locked");
logman("%s:enter", mname);
if (ot == NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (flag != TRUE && flag != FALSE)
{
dbeng_io_code_log(mname, "invalid[flag]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (flag && ot->is_table_locked)
{
dbeng_io_code_log(mname, "table already locked", DBENG_TABLE_LOCKED);
return(DBENG_TABLE_LOCKED);
}
if (flag == ot->is_table_locked)
{
dbeng_io_code_log(mname, "flag is already same value", DBENG_OK);
return(DBENG_OK);
}
if (flag)
ret = dbeng_lock_table(ot);
else
ret = dbeng_unlock_table(ot);
dbeng_io_code_log(mname, "normal exit", ret);
return(ret);
}
int dbeng_lock_table(struct dbeng_table *ot)
{
/* Lock a table. This low level function should only be called
by the function 'dbeng_set_is_table_locked'. This function
does not check the status of the flag first. Every table with
the exact file name will be locked. Function returns
'DBENG_OK' upon success, an error code otherwise. */
struct dbeng_table *rov;
int done = FALSE;
if (dbeng_head == DBENG_OT_NULL)
return(DBENG_NOT_EXIST);
rov = dbeng_head;
while(!done)
{
if (rov == DBENG_OT_NULL)
done = TRUE;
else
{
if (!strcmp(rov->name, ot->name))
rov->is_table_locked = TRUE;
}
if (!done)
rov = rov->next;
}
return(DBENG_OK);
}
int dbeng_unlock_table(struct dbeng_table *ot)
{
/* Unlock a table. This low level function should only be called
by the function 'dbeng_set_is_table_locked'. This function
does not check the status of the flag first. Every table with
the exact file name will be unlocked. Function returns
'DBENG_OK' upon success, an error code otherwise. */
struct dbeng_table *rov;
int done = FALSE;
if (dbeng_head == DBENG_OT_NULL)
return(DBENG_NOT_EXIST);
rov = dbeng_head;
while(!done)
{
if (rov == DBENG_OT_NULL)
done = TRUE;
else
{
if (!strcmp(rov->name, ot->name))
rov->is_table_locked = FALSE;
}
if (!done)
rov = rov->next;
}
return(DBENG_OK);
}
int dbeng_tmp_systable(int *tid)
{
/* Create a new system table with a unique file name.
Function exists with the table open and the table
tid placed into 'tid'. Function returns a 'dbeng' code. */
char mname[] = "dbeng_tmp_systable", *tmp_path, rname[13];
char *table_name;
int ret, tmp_len;
logman("%s:enter", mname);
/* get temporary path from config data */
if ((tmp_path = (char *)malloc(DBENG_PATH_LIMIT)) == (char *)NULL)
{
dbeng_io_code_log(mname, "alloc fail[tmp_path]", DBENG_MEMORY_FAIL);
return(DBENG_MEMORY_FAIL);
}
if ((ret = dbeng_config_get_tmp_path(tmp_path)) != DBENG_OK)
{
dbeng_io_code_log(mname, "error getting tmp path", DBENG_INTERNAL_ERROR);
free(tmp_path);
return(DBENG_INTERNAL_ERROR);
}
logman("%s:before unique", mname);
/* generate a unique file name */
if (!unique(tmp_path, rname))
{
logman("%s:cannot create tmp table[%s%c%s]", mname, tmp_path,
PATH_SEP, rname);
free(tmp_path);
return(DBENG_CANNOT_CREATE_TABLE);
}
logman("%s:after unique", mname);
tmp_len = strlen(tmp_path) + strlen(rname) + 2;
if ((table_name = (char *)malloc(tmp_len)) == (char *) NULL)
{
dbeng_io_code_log(mname, "alloc fail[table_name]",
DBENG_MEMORY_FAIL);
free(tmp_path);
return(DBENG_MEMORY_FAIL);
}
/* build complete path and file name */
sprintf(table_name, "%s%c%s", tmp_path, PATH_SEP, rname);
free(tmp_path);
logman("%s:tmp table is %s", mname, table_name);
/* indicate to also open table in 'dbeng_new_systable' */
*tid = 1;
/* create new empty temporary system table */
if ((ret = dbeng_new_systable(table_name, tid)) != DBENG_OK)
{
logman("%s:new table[%s] create error", mname, table_name);
free(table_name);
return(ret);
}
free(table_name);
dbeng_io_code_log(mname, "normal exit", DBENG_OK);
return(DBENG_OK);
}
int dbeng_new_systable(char *fname, int *tid)
{
/* Create a new system table. If the 'tid' is a positive
integer, also open the table. Function returns
the table 'tid' upon success. Function returns
a 'dbeng' code. */
char mname[] = "dbeng_new_systable";
int ret;
if (fname == (char *)NULL || !strlen(fname))
{
dbeng_io_code_log(mname, "fname parameter error",
DBENG_INVALID_FILE_NAME);
return(DBENG_INVALID_FILE_NAME);
}
logman("%s:enter,fname=%s", mname, fname);
if (tid == (int *)NULL)
{
dbeng_io_code_log(mname, "null[tid]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if ((ret = dbeng_ll_new_table(fname, tid, TRUE)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_ll_new_table", ret);
return(ret);
}
dbeng_io_code_log(mname, "normal exit", DBENG_OK);
return(DBENG_OK);
}
int dbeng_new_table(char *fname, int *tid)
{
/* Create a new table. If the 'tid' is a positive
integer, also open the table. Function returns
the table 'tid' upon success. Function returns
a 'dbeng' code. */
char mname[] = "dbeng_new_table";
int ret;
if (fname == (char *)NULL || !strlen(fname))
{
dbeng_io_code_log(mname, "fname parameter error",
DBENG_INVALID_FILE_NAME);
return(DBENG_INVALID_FILE_NAME);
}
logman("%s:enter,fname=%s", mname, fname);
if (tid == (int *)NULL)
{
dbeng_io_code_log(mname, "null[tid]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if ((ret = dbeng_ll_new_table(fname, tid, FALSE)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_ll_new_table", ret);
return(ret);
}
dbeng_io_code_log(mname, "normal exit", DBENG_OK);
return(DBENG_OK);
}
static int dbeng_ll_new_table(char *table_name, int *tid,
int systable_flag)
{
/* Create a new empty table. If 'tid' is a positive
number, the table will be opened and the TID will be
returned in same. 'table_name' may be in two parts separated
by a comma which will indicate the logical table name
followed by the physical name, ie:
test.primary,/hd1/bbuuzzb/tables/test.buz
Do not put spaces before or after the comma.
If the two part form is used, an entry in the system
catalog will be made (whether or not the catalog flag
is on). An entry with the same logical name must not
already exist. If the two part form is not used, a
physical file name is assumed (do not prefix
the physical file name with 'DBENG_CATALOG_FNAME_IND'
as in 'dbeng_open_table'. Function returns 'DBENG_OK' upon
success, an engine i/o code otherwise. */
char mname[] = "dbeng_ll_new_table";
char *ntable;
int ret;
logman("%s:enter", mname);
if (table_name == (char *)NULL || !strlen(table_name))
{
dbeng_io_code_log(mname, "null or empty[table_name]",
DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (tid == (int *)NULL)
{
dbeng_io_code_log(mname, "null[tid]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
/* add an extra byte to the output table name in case the form
'%name' is returned */
if ((ntable = (char *)malloc(strlen(table_name) + 2)) == (char *)NULL)
{
dbeng_io_code_log(mname, "alloc fail[ntable]", DBENG_MEMORY_FAIL);
return(DBENG_MEMORY_FAIL);
}
/* derive proper name that will be given to 'new.table',
create the new empty file and catalog entry (if required) */
if ((ret = dbeng_catalog_new_table(table_name, ntable, systable_flag))
!= DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_catalog_new_table", ret);
free(ntable);
return(ret);
}
/* strcpy(ntable, table_name);
if (!zcreate(ntable))
{
dbeng_io_code_log(mname, "error creating empty table",
DBENG_CANNOT_CREATE_TABLE);
free(ntable);
return(DBENG_CANNOT_CREATE_TABLE);
} */
if (*tid > 0)
{
ret = dbeng_ll_open_table(ntable, tid, systable_flag);
dbeng_io_code_log(mname, "normal exit[with open]", ret);
free(ntable);
return(ret);
}
dbeng_io_code_log(mname, "normal exit", DBENG_OK);
free(ntable);
return(DBENG_OK);
}
int dbeng_delete_table(char *fname)
{
/* Delete a 'dbeng' (Bbuuzzb) table by name. The catalog will be
used to obtain the physical file name if the catalog
flag is high. Both catalog entry and physical file
will be deleted. The table must not be in current use by
any other 'tid'. Function returns a 'dbeng' code. */
struct dbeng_table *ot;
char mname[] = "dbeng_delete_table", *pname;
int ret, tid, catalog_flag;
logman("%s:enter", mname);
if (fname == (char *)NULL || !strlen(fname))
{
dbeng_io_code_log(mname, "null or empty[fname]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
/* verify table (and possibly catalog entry) by attempting
to open the table */
if ((ret = dbeng_open_table(fname, &tid)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_open_table", ret);
return(ret);
}
/* get pointer to structure and get physical file name */
if ((ot = dbeng_atid_lookup(tid)) == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "error getting table pointer",
DBENG_INTERNAL_ERROR);
return(DBENG_INTERNAL_ERROR);
}
/* copy physical file name */
if (ot->name == (char *)NULL || !strlen(ot->name))
{
dbeng_io_code_log(mname, "null or empty[ot->name]", DBENG_INTERNAL_ERROR);
return(DBENG_INTERNAL_ERROR);
}
if ((pname = initstring(ot->name)) == (char *)NULL)
{
dbeng_io_code_log(mname, "alloc fail[pname]", DBENG_MEMORY_FAIL);
return(DBENG_MEMORY_FAIL);
}
/* close table (if the session flag is high the physical file
will already have been closed) */
if ((ret = dbeng_close_table(ot)) != DBENG_OK)
/* we might get a non-ok if the session table is active */
dbeng_io_code_log(mname, "bad rc from dbeng_close_table", ret);
/* make sure table is not in use by other tid's */
if (dbeng_table_in_use(pname))
{
free(pname);
dbeng_io_code_log(mname, "unable to delete table", DBENG_TABLE_IN_USE);
return(DBENG_TABLE_IN_USE);
}
unlink(pname);
free(pname);
/* if catalog flag is high, attempt to obtain and delete
the catalog entry (might fail if only the physical
file name was supplied) */
(void)dbeng_config_get_catalog_flag(&catalog_flag);
if (catalog_flag)
if ((ret = dbeng_catalog_delete(fname)) != DBENG_OK)
dbeng_io_code_log(mname, "bad rc from dbeng_catalog_delete", ret);
dbeng_io_code_log(mname, "normal exit", DBENG_OK);
return(DBENG_OK);
}
int dbeng_open_table_list(char *pat, char *list_out)
{
/* Return the list of open tables. List is
returned in 'list_out' which must be already
allocated to sufficient size. The list is delimited
by 'DEBNG_LIST_DELIM'. Each entry in the list contains
the tid in use followed by the file path/name. The two
fields in the list are delimited by a comma.
The parameter 'pat' may contain a table path/file pattern
acceptable to the 'pmatch' function. If 'pat' is
'NULL' or empty, all tables in use
will be returned. Function returns a 'dbeng' code. */
struct dbeng_table *rov;
char *before, *after, *wdata;
char mname[] = "dbeng_open_table_list";
int cnt, is_pat, process;
logman("%s:enter", mname);
if (list_out == (char *)NULL)
{
dbeng_io_code_log(mname, "null[list_out]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
is_pat = (pat == (char *)NULL || !strlen(pat)) ? FALSE : TRUE;
if (is_pat)
logman("%s:pat=%s", mname, pat);
list_out[0] = EOS;
rov = dbeng_head;
/* it is not an error if the list is empty */
if (rov == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "list is empty", DBENG_OK);
return(DBENG_OK);
}
if ((before = (char *)malloc(DBENG_MAXRECFIELD)) == (char *)NULL)
{
dbeng_io_code_log(mname, "alloc fail[before]", DBENG_MEMORY_FAIL);
return(DBENG_MEMORY_FAIL);
}
if ((after = (char *)malloc(DBENG_MAXRECFIELD)) == (char *)NULL)
{
dbeng_io_code_log(mname, "alloc fail[after]", DBENG_MEMORY_FAIL);
free(before);
return(DBENG_MEMORY_FAIL);
}
if ((wdata = (char *)malloc(1023)) == (char *)NULL)
{
dbeng_io_code_log(mname, "alloc fail[wdata]", DBENG_MEMORY_FAIL);
free(before);
free(after);
return(DBENG_MEMORY_FAIL);
}
before[0] = after[0] = EOS;
cnt = 1;
while(rov != DBENG_OT_NULL)
{
process = TRUE;
/* match physical file name to pattern (if supplied) */
if (is_pat)
if (!pmatch(pat, rov->name))
{
process = FALSE;
logman("%s:%s is no match", mname, rov->name);
}
else
logman("%s:%s is a match", mname, rov->name);
if (process)
{
sprintf(wdata, "%d,%s", rov->tid, rov->name);
if (!ll_wordput(before, after, wdata, cnt, DBENG_LIST_DELIM))
{
dbeng_io_code_log(mname, "error putting list item",
DBENG_INTERNAL_ERROR);
free(before);
free(after);
free(wdata);
return(DBENG_INTERNAL_ERROR);
}
cnt++;
strcpy(before, after);
}
rov = rov->next;
}
strcpy(list_out, after);
free(before);
free(after);
free(wdata);
dbeng_io_code_log(mname, "normal exit", DBENG_OK);
return(DBENG_OK);
}
int dbeng_exist(char *tname, int *exist_flag)
{
/* Determine whether a database table exists. Naming
convention is the same as for 'dbeng_open_table'.
The flag 'exist_flag' will be loaded with the
exist flag (TRUE=table exists). Function returns
a 'dbeng' code. */
struct dbeng_table *ot;
char mname[] = "dbeng_exist";
int ret, tid;
logman("%s:enter", mname);
if (tname == (char *)NULL || !strlen(tname))
{
dbeng_io_code_log(mname, "null or empty[tname]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (exist_flag == (int *)NULL)
{
dbeng_io_code_log(mname, "null[exist_flag]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
*exist_flag = FALSE;
if ((ret = dbeng_open_table(tname, &tid)) != DBENG_OK)
{
dbeng_io_code_log(mname, "exit:table does not exist", DBENG_OK);
return(DBENG_OK);
}
if ((ot = dbeng_atid_lookup(tid)) == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "bad rc from dbeng_atid_lookup",
DBENG_INTERNAL_ERROR);
return(DBENG_INTERNAL_ERROR);
}
(void)dbeng_close_table(ot);
*exist_flag = TRUE;
dbeng_io_code_log(mname, "exit:table does exist", DBENG_OK);
return(DBENG_OK);
}
int dbeng_clear_table(char *tname)
{
/* Clear a table of all records by deleting the table and
re-creating it. The table must not already be in use.
Function returns a 'dbeng' code. */
struct dbeng_table *rov;
char mname[] = "dbeng_clear_table", *fname;
int ret, tid, len, systable_flag = FALSE;
logman("%s:enter", mname);
if (tname == (char *)NULL || !strlen(tname))
{
dbeng_io_code_log(mname, "null or empty[tname]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
#ifdef MULTIUSER
// check for session table
if (dbeng_config_is_session(tname))
systable_flag = TRUE;
#endif
// check for catalog
if (!systable_flag && dbeng_config_is_catalog(tname))
systable_flag = TRUE;
if (systable_flag)
{
/* if it is either the session table or the catalog,
the name is already the physical file name, just
copy it */
if ((fname = (char *)malloc(strlen(tname) + 1)) == (char *)NULL)
{
dbeng_io_code_log(mname, "alloc fail[fname]", DBENG_MEMORY_FAIL);
return(DBENG_MEMORY_FAIL);
}
strcpy(fname, tname);
}
/* open the table to make sure we access it's physical file name */
if (!systable_flag)
{
if ((ret = dbeng_open_table(tname, &tid)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_open_table", ret);
return(ret);
}
if ((rov = dbeng_atid_lookup(tid)) == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "bad rc[NULL] from dbeng_atid_lookup",
DBENG_INTERNAL_ERROR);
return(DBENG_INTERNAL_ERROR);
}
if ((len = strlen(rov->name)) == 0)
{
dbeng_io_code_log(mname, "table physical file name is empty",
DBENG_INTERNAL_ERROR);
return(DBENG_INTERNAL_ERROR);
}
if ((fname = (char *)malloc(len + 1)) == (char *)NULL)
{
dbeng_io_code_log(mname, "alloc fail[fname]", DBENG_MEMORY_FAIL);
return(DBENG_MEMORY_FAIL);
}
strcpy(fname, rov->name);
(void)dbeng_close_table(rov);
}
/* if the table is in use by other tid's, refuse */
if (dbeng_table_in_use(fname))
{
free(fname);
dbeng_io_code_log(mname, "unable to clear table", DBENG_TABLE_IN_USE);
return(DBENG_TABLE_IN_USE);
}
unlink(fname);
if (!zcreate(fname))
{
dbeng_io_code_log(mname, "error creating new empty table",
DBENG_INTERNAL_ERROR);
free(fname);
return(DBENG_INTERNAL_ERROR);
}
free(fname);
dbeng_io_code_log(mname, "normal exit", DBENG_OK);
return(DBENG_OK);
}
int dbeng_ll_open(struct dbeng_table *ot)
{
/* Open the file associated with the table 'ot'.
File will only be open if the 'handle' is
null. Function returns 'DBENG_OK' upon
success, an engine i/o code otherwise. */
char mname[] = "dbeng_ll_open";
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 (ot->handle != (FILE *)NULL)
{
dbeng_io_code_log(mname, "exit:file already open",
DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if ((ot->handle = fopen(ot->name, "rb+")) == (FILE *)NULL)
{
dbeng_io_code_log(mname, "exit:cannot open file", DBENG_UNABLE_TO_OPEN);
return(DBENG_UNABLE_TO_OPEN);
}
/* assign a buffer */
/* if (setvbuf(ot->handle, NULL, _IOFBF, DBENG_IO_BUF_SIZE))
{
fclose(ot->handle);
dbeng_io_code_log(mname, "exit:error 'setvbuf' on file",
DBENG_UNABLE_TO_OPEN);
return(DBENG_UNABLE_TO_OPEN);
} */
/* reset file position */
if (ot->current_position > 0L)
fseek(ot->handle, ot->current_position, 0);
dbeng_io_code_log(mname, "normal exit", DBENG_OK);
return(DBENG_OK);
}
int dbeng_ll_close(struct dbeng_table *ot)
{
/* Close the file handle associated with the table 'ot'.
Function returns 'DBENG_OK' upon success, an engine
i/o code otherwise. */
char mname[] = "dbeng_ll_close";
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "exit:null ot", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
logman("%s:enter:tid=%d", mname, ot->tid);
if (ot->handle == (FILE *)NULL)
{
dbeng_io_code_log(mname, "exit:file not open", DBENG_NO_SUCH_FILE);
return(DBENG_NO_SUCH_FILE);
}
fclose(ot->handle);
ot->handle = (FILE *)NULL;
dbeng_io_code_log(mname, "normal exit", DBENG_OK);
return(DBENG_OK);
}
int dbeng_is_systable(struct dbeng_table *ot, int *flag)
{
/* Obtain the current 'is_systable' value. Function
returns the value of the flag in 'flag' and 'DBENG_OK' upon
success, an error code otherwise. */
char mname[] = "dbeng_is_systable";
logman("%s:enter", mname);
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (flag == NULL)
{
dbeng_io_code_log(mname, "null[flag]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
*flag = ot->is_systable;
dbeng_io_code_log(mname, "normal exit", DBENG_OK);
return(DBENG_OK);
}
int dbeng_copy_table(struct dbeng_table *src, struct dbeng_table *dest)
{
/* Copy a table from source ('src') to destination ('dest'). No
regard is given to the existing contents of the destination
table (if any). Function returns a 'dbeng' code. */
char mname[] = "dbeng_copy_table";
int ret, session_flag;
logman("%s:enter", mname);
if (src == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[src]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (dest == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[dest]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
/* check for changed records in both source and destination table */
if (src->enforce_change_rec_flag && src->change_rec_flag)
{
dbeng_io_code_log(mname, "record changed", DBENG_RECORD_CHANGED);
return(DBENG_RECORD_CHANGED);
}
if (dest->enforce_change_rec_flag && dest->change_rec_flag)
{
dbeng_io_code_log(mname, "record changed", DBENG_RECORD_CHANGED);
return(DBENG_RECORD_CHANGED);
}
#ifdef MULTIUSER
/* if the session table is active, the source table will be open
but not the destination table, we open it here */
(void)dbeng_config_get_session_flag(&session_flag);
if (session_flag)
(void)dbeng_ll_open(dest);
#endif
/* use 'dbeng_ll_copy_table' to copy */
if ((ret = dbeng_ll_copy_table(src, dest)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad ret from dbeng_ll_copy_table", ret);
return(ret);
}
#ifdef MULTIUSER
if (session_flag)
(void)dbeng_ll_close(dest);
#endif
dbeng_io_code_log(mname, "normal exit", ret);
return(ret);
}
static int dbeng_record_header(struct dbeng_table *ot, int *len, char *status)
{
/* Read and verify the record header which is assumed to start
at the current file position. Upon success, the record
length is returned in 'len' and the record status is
returned in 'status'. Function returns a 'dbeng' code. */
char rec_head[DBENG_REC_HEAD_SIZE + 1];
char mname[] = "dbeng_record_header";
int rlen, bytes_read;
/* logman("%s:enter", mname); */
if (len == (int *)NULL)
{
dbeng_io_code_log(mname, "null[len]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (status == (char *)NULL)
{
dbeng_io_code_log(mname, "null[status]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
/* read record header, assume record pointer is at start of header */
bytes_read = fread(rec_head, 1, DBENG_REC_HEAD_SIZE, ot->handle);
if (bytes_read < DBENG_REC_HEAD_SIZE)
{
logman("%s:exit:eof detected,tid=%d", mname, ot->tid);
return(DBENG_EOF);
}
/* error if field mark not present */
if ((unsigned char)rec_head[DBENG_REC_HEAD_SIZE - 1] != DBENG_FM)
{
rec_head[DBENG_REC_HEAD_SIZE - 1] = EOS;
logman("%s:no field mark at end of header:tid=%d,rh=%s,l=%d,rc=%d",
mname, ot->tid, rec_head, strlen(rec_head),
DBENG_FILE_DATA_ERROR);
return(DBENG_FILE_DATA_ERROR);
}
/* remove field separator */
rec_head[DBENG_REC_HEAD_SIZE - 1] = EOS;
/* attempt to get record length */
if (!qatoi(&rec_head[1], &rlen))
{
dbeng_io_code_log(mname, "error:header length is non-numeric",
DBENG_FILE_DATA_ERROR);
return(DBENG_FILE_DATA_ERROR);
}
*len = rlen;
*status = rec_head[0];
/* dbeng_io_code_log(mname, "normal exit", DBENG_OK); */
return(DBENG_OK);
}
static int dbeng_put_which_field(struct dbeng_table *ot, int fnum,
int *new_fnum)
{
/* Determine which field to put data into. A positive integer
is assumed to be the absolute field number. A zero indicates
to append a new field to the record. Function returns the
field number loaded into 'new_fnum' upon success. Function
returns a 'dbeng' code. */
char mname[] = "dbeng_put_which_field";
int nfields, ret;
logman("%s:enter:fnum=%d", mname, fnum);
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (new_fnum == (int *)NULL)
{
dbeng_io_code_log(mname, "null[new_fnum]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
*new_fnum = 0;
if (fnum < 0)
{
dbeng_io_code_log(mname, "out of range[fnum]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (fnum > 0)
{
logman("%s:normal exit,new_fnum=%d", mname, fnum);
*new_fnum = fnum;
return(DBENG_OK);
}
if ((ret = dbeng_nfields(ot, &nfields)) != DBENG_OK)
if (ret == DBENG_NO_RECORD)
nfields = 0;
else
{
dbeng_io_code_log(mname, "bad rc from dbeng_nfields", ret);
return(ret);
}
logman("%s:normal exit,new_fnum=%d", mname, nfields + 1);
*new_fnum = nfields + 1;
return(DBENG_OK);
}
static int dbeng_put_which_subfield(struct dbeng_table *ot, int fnum,
int sfnum, int *new_fnum, int *new_sfnum)
{
/* Determine which field and subfield to put data into. A positive
integer is assumed to be the absolute field/subfield number. A zero
indicates to append a new field/subfield to the record. Function
returns the field number loaded into 'new_fnum' and the new
subfield number loaded into 'new_sfnum' upon success. Function
returns a 'dbeng' code. */
char mname[] = "dbeng_put_which_subfield";
int nsubfields, ret;
logman("%s:enter:fnum=%d,sfnum=%d", mname, fnum, sfnum);
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (new_fnum == (int *)NULL)
{
dbeng_io_code_log(mname, "null[new_fnum]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (new_sfnum == (int *)NULL)
{
dbeng_io_code_log(mname, "null[new_sfnum]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
*new_fnum = *new_sfnum = 0;
if (sfnum < 0)
{
dbeng_io_code_log(mname, "out of range[sfnum]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if ((ret = dbeng_put_which_field(ot, fnum, new_fnum)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_put_which_field", ret);
return(ret);
}
/* if the field number was zero, set subfield number and exit */
if (!fnum)
{
if (!sfnum)
*new_sfnum = 1;
else
*new_sfnum = sfnum;
logman("%s:exit[0]:new_fnum=%d,new_sfnum=%d", mname,
*new_fnum, *new_sfnum);
return(DBENG_OK);
}
/* if the field number was not zero and subfield was not zero,
set subfield and exit */
if (sfnum)
{
*new_sfnum = sfnum;
logman("%s:exit[0]:new_fnum=%d,new_sfnum=%d", mname,
*new_fnum, *new_sfnum);
return(DBENG_OK);
}
/* field number was not zero and subfield was zero */
ret = dbeng_nsubfields(ot, *new_fnum, &nsubfields);
switch(ret)
{
case DBENG_OK:
*new_sfnum = nsubfields + 1;
break;
case DBENG_NO_SUCH_FIELD:
case DBENG_NO_RECORD:
*new_sfnum = 1;
ret = DBENG_OK;
break;
default:
dbeng_io_code_log(mname, "bad rc from dbeng_nsubfields", ret);
*new_fnum = *new_sfnum = 0;
};
logman("%s:exit[0]:new_fnum=%d,new_sfnum=%d", mname,
*new_fnum, *new_sfnum);
return(ret);
}
static int dbeng_put_which_subsubfield(struct dbeng_table *ot, int fnum,
int sfnum, int ssfnum, int *new_fnum,
int *new_sfnum, int *new_ssfnum)
{
/* Determine which field, subfield and subsubfield to put data into.
A positive integer is assumed to be the absolute
field/subfield/subsubfield number. A zero indicates to append a new
field/subfield/subsubfield to the record. Function returns the field
number loaded into 'new_fnum', the new subfield number loaded into
'new_sfnum' and the new subsubfield number loaded into 'new_ssfnum'
upon success. Function returns a 'dbeng' code. */
char mname[] = "dbeng_put_which_subsubfield";
int nsubsubfields, ret;
logman("%s:enter:fnum=%d,sfnum=%d,ssfnum=%d", mname, fnum, sfnum,
ssfnum);
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (new_fnum == (int *)NULL)
{
dbeng_io_code_log(mname, "null[new_fnum]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (new_sfnum == (int *)NULL)
{
dbeng_io_code_log(mname, "null[new_sfnum]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (new_ssfnum == (int *)NULL)
{
dbeng_io_code_log(mname, "null[new_ssfnum]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
*new_fnum = *new_sfnum = *new_ssfnum = 0;
if (ssfnum < 0)
{
dbeng_io_code_log(mname, "out of range[ssfnum]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if ((ret = dbeng_put_which_subfield(ot, fnum, sfnum, new_fnum, new_sfnum))
!= DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_put_which_subfield", ret);
return(ret);
}
/* subsubfield number was not zero */
if (ssfnum)
{
*new_ssfnum = ssfnum;
logman("%s:exit[0]:new_fnum=%d,new_sfnum=%d,new_ssfnum=%d", mname,
*new_fnum, *new_sfnum, *new_ssfnum);
return(DBENG_OK);
}
/* subsubfield number zero */
ret = dbeng_nsubsubfields(ot, *new_fnum, *new_sfnum, &nsubsubfields);
switch(ret)
{
case DBENG_OK:
*new_ssfnum = nsubsubfields + 1;
break;
case DBENG_NO_SUCH_SUBFIELD:
case DBENG_NO_SUCH_FIELD:
case DBENG_NO_RECORD:
*new_ssfnum = 1;
ret = DBENG_OK;
break;
default:
dbeng_io_code_log(mname, "bad rc from dbeng_nsubsubfields", ret);
*new_fnum = *new_sfnum = *new_ssfnum = 0;
};
logman("%s:exit[0]:new_fnum=%d,new_sfnum=%d,new_ssfnum=%d", mname,
*new_fnum, *new_sfnum, *new_ssfnum);
return(ret);
}
static int dbeng_ll_copy_table(struct dbeng_table *src,
struct dbeng_table *dest)
{
/* Copy a table from source ('src') to destination ('dest').
Both tables are assumed to be open. No regard is given to
existing contents of destination table. Records are copied
in accordance with the current value of the source table
'process_deleted' flag. Function exits with the tables
remaining open. Function returns a 'dbeng' code. */
#ifdef MULTIUSER
struct dbeng_table *rov;
int pos_changed;
#endif
char mname[] = "dbeng_ll_copy_table";
int ret, done;
logman("%s:enter", mname);
if (src == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[src]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (dest == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[dest]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
logman("%s:src:tid=%d,name=%s:dest:tid=%d,name=%s", mname,
src->tid, src->name, dest->tid, dest->name);
/* goto top of source table */
if ((ret = dbeng_goto_top(src)) != DBENG_OK)
{
dbeng_io_code_log(mname, "error going to top", ret);
return(ret);
}
done = FALSE;
/* get first source record */
ret = dbeng_get_recd(src);
if (ret != DBENG_OK)
if (ret == DBENG_EOF)
{
done = TRUE;
dbeng_io_code_log(mname, "source table empty", ret);
}
else
{
dbeng_io_code_log(mname, "error getting first sourc rec", ret);
return(ret);
}
/* read/write loop */
while(!done)
{
/* reconcile any other tid pointing to this record
and fix-up any incorrect file positions */
#ifdef MULTIUSER
rov = dbeng_head;
pos_changed = FALSE;
while(rov != DBENG_OT_NULL)
{
/* if the tid's are different and the table file names are the same */
if (src->tid != rov->tid && !strcmp(src->name, rov->name))
{
/* if the start record position is the same */
if (src->orig_position == rov->orig_position)
{
logman("%s:orig_position fix-up:itid=%d,ltid=%d"
",pos=%ld", mname, src->tid, rov->tid,
src->orig_position);
/* change link list start record position to match current
output position */
rov->orig_position = dest->current_position;
rov->current_position = -1L;
pos_changed = TRUE;
}
}
rov = rov->next;
}
#endif
// write record
ret = dbeng_write_string_recd(dest, src->rec);
if (ret != DBENG_OK)
{
dbeng_io_code_log(mname, "error writing record", ret);
return(ret);
}
#ifdef MULTIUSER
/* fix-up link list current file positions, if required */
if (pos_changed)
{
rov = dbeng_head;
while(rov != DBENG_OT_NULL)
{
/* if the start record position has been modified,
fix-up the current/end of record position */
if (rov->current_position == -1L)
{
logman("%s:current_position fix-up:itid=%d"
",ltid=%d,lopos=%ld,lcpos=%ld", mname, src->tid,
rov->tid, rov->orig_position,
dest->current_position);
/* change link list current position to match current
output position */
rov->current_position = dest->current_position;
}
rov = rov->next;
}
}
#endif
/* get next source record */
ret = dbeng_get_recd(src);
switch(ret)
{
case DBENG_EOF:
done = TRUE;
break;
case DBENG_OK:
done = FALSE;
break;
/* we should never get here, just in case */
default:
dbeng_io_code_log(mname, "error getting record", ret);
return(ret);
};
}
dbeng_io_code_log(mname, "normal exit", DBENG_OK);
return(DBENG_OK);
}
int dbeng_delete_field(struct dbeng_table *ot, int fnum)
{
/* Completely remove the 'fnum' field from the current record.
Note that all field numbers past the field being deleted
will change. Function returns a 'dbeng' code. */
char mname[] = "dbeng_delete_field", *new_rec;
int num_fields;
logman("%s:enter", mname);
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (fnum <= 0)
{
dbeng_io_code_log(mname, "out of range[fnum]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (dbeng_is_active_rec(ot) == DBENG_NO_RECORD)
{
dbeng_io_code_log(mname, "no current record", DBENG_NO_RECORD);
return(DBENG_NO_RECORD);
}
num_fields = ll_words(ot->rec, DBENG_FM);
if (fnum > num_fields)
{
dbeng_io_code_log(mname, "not exist[fnum field]", DBENG_NO_SUCH_FIELD);
return(DBENG_NO_SUCH_FIELD);
}
if ((new_rec = initstring(ot->rec)) == (char *)NULL)
{
dbeng_io_code_log(mname, "alloc fail[new_rec]", DBENG_MEMORY_FAIL);
return(DBENG_MEMORY_FAIL);
}
new_rec[0] = EOS;
if (!ll_worddel(ot->rec, new_rec, fnum, DBENG_FM))
{
dbeng_io_code_log(mname, "bad rc[FALSE] from ll_worddel",
DBENG_INTERNAL_ERROR);
free(new_rec);
return(DBENG_INTERNAL_ERROR);
}
free(ot->rec);
if ((ot->rec = initstring(new_rec)) == (char *)NULL)
{
dbeng_io_code_log(mname, "alloc fail[ot->rec]", DBENG_MEMORY_FAIL);
free(new_rec);
return(DBENG_MEMORY_FAIL);
}
free(new_rec);
dbeng_io_code_log(mname, "normal exit", DBENG_OK);
return(DBENG_OK);
}
int dbeng_delete_subfield(struct dbeng_table *ot, int fnum, int sfnum)
{
/* Completely remove a subfield from the current record.
Function returns a 'dbeng' code. */
char mname[] = "dbeng_delete_subfield", *tfield, *nfield;
int ret, num_fields, fsize, num_subfields;
logman("%s:enter", mname);
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (fnum <= 0)
{
dbeng_io_code_log(mname, "out of range[fnum]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (sfnum <= 0)
{
dbeng_io_code_log(mname, "out of range[sfnum]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (dbeng_is_active_rec(ot) == DBENG_NO_RECORD)
{
dbeng_io_code_log(mname, "no current record", DBENG_NO_RECORD);
return(DBENG_NO_RECORD);
}
num_fields = ll_words(ot->rec, DBENG_FM);
if (fnum > num_fields)
{
dbeng_io_code_log(mname, "not exist[fnum field]", DBENG_NO_SUCH_FIELD);
return(DBENG_NO_SUCH_FIELD);
}
// obtain the field where the subfield is contained
if ((ret = dbeng_field_size(ot, fnum, &fsize)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_field_size", ret);
return(ret);
}
if ((tfield = (char *)malloc(fsize + 1)) == (char *)NULL)
{
dbeng_io_code_log(mname, "alloc fail[tfield]", DBENG_MEMORY_FAIL);
return(DBENG_MEMORY_FAIL);
}
if (!ll_word(ot->rec, tfield, fnum, DBENG_FM))
{
dbeng_io_code_log(mname, "bad rc[FALSE] from ll_word",
DBENG_INTERNAL_ERROR);
free(tfield);
return(DBENG_INTERNAL_ERROR);
}
num_subfields = ll_words(tfield, DBENG_SFM);
if (sfnum > num_subfields)
{
dbeng_io_code_log(mname, "not exist[sfnum subfield]",
DBENG_NO_SUCH_SUBFIELD);
free(tfield);
return(DBENG_NO_SUCH_SUBFIELD);
}
if ((nfield = initstring(tfield)) == (char *)NULL)
{
dbeng_io_code_log(mname, "alloc fail[nfield]", DBENG_MEMORY_FAIL);
free(tfield);
return(DBENG_MEMORY_FAIL);
}
nfield[0] = EOS;
if (!ll_worddel(tfield, nfield, sfnum, DBENG_SFM))
{
dbeng_io_code_log(mname, "bad rc[FALSE] from ll_worddel",
DBENG_INTERNAL_ERROR);
free(tfield);
free(nfield);
return(DBENG_INTERNAL_ERROR);
}
free(tfield);
// put new field back into record
if ((ret = dbeng_put_field(ot, nfield, fnum)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_put_field", ret);
free(nfield);
return(ret);
}
free(nfield);
dbeng_io_code_log(mname, "normal exit", DBENG_OK);
return(DBENG_OK);
}
int dbeng_delete_subsubfield(struct dbeng_table *ot, int fnum, int sfnum,
int ssfnum)
{
/* Completely remove a subsubfield from the current record.
Function returns a 'dbeng' code. */
char mname[] = "dbeng_delete_subsubfield", *tsubfield, *nsubfield;
int ret, num_subfields, sfsize, num_subsubfields, num_fields;
logman("%s:enter", mname);
if (ot == DBENG_OT_NULL)
{
dbeng_io_code_log(mname, "null[ot]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (fnum <= 0)
{
dbeng_io_code_log(mname, "out of range[fnum]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (sfnum <= 0)
{
dbeng_io_code_log(mname, "out of range[sfnum]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (ssfnum <= 0)
{
dbeng_io_code_log(mname, "out of range[ssfnum]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (dbeng_is_active_rec(ot) == DBENG_NO_RECORD)
{
dbeng_io_code_log(mname, "no current record", DBENG_NO_RECORD);
return(DBENG_NO_RECORD);
}
num_fields = ll_words(ot->rec, DBENG_FM);
if (fnum > num_fields)
{
dbeng_io_code_log(mname, "not exist[fnum field]", DBENG_NO_SUCH_FIELD);
return(DBENG_NO_SUCH_FIELD);
}
if ((ret = dbeng_nsubfields(ot, fnum, &num_subfields)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_nsubfields", ret);
return(ret);
}
if (sfnum > num_subfields)
{
dbeng_io_code_log(mname, "not exist[sfnum subfield]",
DBENG_NO_SUCH_SUBFIELD);
return(DBENG_NO_SUCH_SUBFIELD);
}
// obtain the subfield where the subsubfield is contained
if ((ret = dbeng_subfield_size(ot, fnum, sfnum, &sfsize)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_subfield_size", ret);
return(ret);
}
if ((tsubfield = (char *)malloc(sfsize + 1)) == (char *)NULL)
{
dbeng_io_code_log(mname, "alloc fail[tsubfield]", DBENG_MEMORY_FAIL);
return(DBENG_MEMORY_FAIL);
}
if ((ret = dbeng_get_subfield(ot, tsubfield, fnum, sfnum)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_get_subfield", ret);
free(tsubfield);
return(ret);
}
num_subsubfields = ll_words(tsubfield, DBENG_SSFM);
if (ssfnum > num_subsubfields)
{
dbeng_io_code_log(mname, "not exist[ssfnum subsubfield]",
DBENG_NO_SUCH_SUBSUBFIELD);
free(tsubfield);
return(DBENG_NO_SUCH_SUBSUBFIELD);
}
if ((nsubfield = initstring(tsubfield)) == (char *)NULL)
{
dbeng_io_code_log(mname, "alloc fail[nsubfield]", DBENG_MEMORY_FAIL);
free(tsubfield);
return(DBENG_MEMORY_FAIL);
}
if (!ll_worddel(tsubfield, nsubfield, ssfnum, DBENG_SSFM))
{
dbeng_io_code_log(mname, "bad rc[FALSE] from ll_worddel",
DBENG_INTERNAL_ERROR);
free(tsubfield);
free(nsubfield);
return(DBENG_INTERNAL_ERROR);
}
free(tsubfield);
// put new subfield back into record
if ((ret = dbeng_put_subfield(ot, nsubfield, fnum, sfnum)) != DBENG_OK)
{
dbeng_io_code_log(mname, "bad rc from dbeng_put_subfield", ret);
free(nsubfield);
return(ret);
}
free(nsubfield);
dbeng_io_code_log(mname, "normal exit", DBENG_OK);
return(DBENG_OK);
}
int dbeng_set_record_count(struct dbeng_table *ot)
{
/* Check all open tables and adjust the active and deleted
record count to the current table counts. Function
returns a 'dbeng' code. */
struct dbeng_table *rov = dbeng_head;
// logman("%s:enter:tid=%d", mname, ot->tid);
while(rov != DBENG_OT_NULL)
{
if (ot != rov)
{
if (!strcmp(ot->name, rov->name))
{
rov->active_record_count = ot->active_record_count;
rov->deleted_record_count = ot->deleted_record_count;
}
}
rov = rov->next;
}
// logman("%s:exit[%d]", mname, DBENG_OK);
return(DBENG_OK);
}
void dbeng_terminate(void)
{
/* Close all tables and de-allocate
all memory in use. */
struct dbeng_table *t_cur;
char mname[50];
int done = FALSE;
strcpy(mname, "dbeng_terminate");
logman("%s:enter", mname);
while(!done)
{
t_cur = dbeng_head;
if (t_cur == DBENG_OT_NULL)
done = TRUE;
else
(void)dbeng_close_table(t_cur);
}
logman("%s:normal exit", mname);
}
int dbeng_is_active_rec(struct dbeng_table *ot)
{
/* Check for active table record. Function returns
'DBENG_NO_RECORD' if no active table record is
present, 'DBENG_OK' otherwise. */
if (ot == DBENG_OT_NULL)
return(DBENG_NO_RECORD);
if (ot->rec == (char *)NULL)
return(DBENG_NO_RECORD);
if (!strlen(ot->rec))
return(DBENG_NO_RECORD);
return(DBENG_OK);
}
int dbeng_initialize(void)
{
/* Initialize for database use. Must be called at the beginning
of each session. */
dbeng_table_count = 0;
dbeng_head = DBENG_OT_NULL;
/* load configuration details */
return(dbeng_config_read(DBENG_CONFIG_FILE));
}
int dbeng_get_tid(void)
{
/* Obtain the next table ID. The next tid is based on the
number of tables currently in use. */
int tid, done = FALSE;
tid = dbeng_table_count;
while(!done)
{
tid++;
/* check the tid against all currently open tables */
if (dbeng_atid_lookup(tid) == DBENG_OT_NULL)
done = TRUE;
}
return(tid);
}
static int dbeng_table_in_use(char *fname)
{
/* Determine whether a table is in use by its physical file name.
Function returns 'TRUE' if the table is in use, 'FALSE' otherwise. */
struct dbeng_table *rov = dbeng_head;
char mname[] = "dbeng_table_in_use";
logman("%s:enter:fname=%s", fname);
while(rov != DBENG_OT_NULL)
{
if (!strcmp(rov->name, fname))
{
logman("%s:normal exit[1]:found entry:table is in use", mname);
return(TRUE);
}
rov = rov->next;
}
logman("%s:normal exit[0]:table not in use", mname);
return(FALSE);
}
static int dbeng_compare_field(char *field_data, char *find_str, int cs_flag,
int *result)
{
/* Compare the field data to the find string according to the
case sensitivity flag (1=insensitive,0=sensitive). The
field data and/or the find string may be empty (but not
NULL). Function returns a 'dbeng' code with the result
of the comparison (0=equal) in 'result'. */
char mname[] = "dbeng_compare_field";
int len_fd, len_fs;
if (field_data == (char *)NULL)
{
dbeng_io_code_log(mname, "null[field_data]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
if (find_str == (char *)NULL)
{
dbeng_io_code_log(mname, "null[find_str]", DBENG_INVALID_FUNCTION);
return(DBENG_INVALID_FUNCTION);
}
len_fd = strlen(field_data);
len_fs = strlen(find_str);
*result = -1;
/* if lengths are not the same, cannot possibly be the same */
if (len_fd != len_fs)
{
*result = -1;
return(DBENG_OK);
}
/* if the field data is empty and the find string is empty,
comparison is equal */
if (!len_fd && !len_fs)
{
*result = 0;
return(DBENG_OK);
}
if (cs_flag)
*result = stricmp(field_data, find_str);
else
*result = strcmp(field_data, find_str);
return(DBENG_OK);
}
struct dbeng_table *dbeng_atid_lookup(int tid)
{
/* Take a table tid and perform a lookup.
Function returns a pointer to the found table
upon success, a 'NULL' pointer otherwise. */
struct dbeng_table *ot;
int done = FALSE;
int found = FALSE;
if (dbeng_head == DBENG_OT_NULL)
return((struct dbeng_table *)NULL);
if (tid <= 0)
return((struct dbeng_table *)NULL);
ot = dbeng_head;
while(!done)
{
if (ot == DBENG_OT_NULL)
done = TRUE;
else
{
if (ot->tid == tid)
{
done = TRUE;
found = TRUE;
}
}
if (!done && !found)
ot = ot->next;
}
if (!found)
ot = (struct dbeng_table *)NULL;
return(ot);
}
void dbeng_ferror(char *mess)
{
/* Output a message via the log manager.
The message will always be logged and the existing status
of logging will be preserved. */
int islog;
char *apname, *err_log;
islog = logman_is_active();
if (!islog)
{
if ((apname = (char *)malloc(DBENG_PATH_LIMIT)) == (char *)NULL)
return;
#ifndef OS_DOS
if (!appinit_get_name(apname))
{
free(apname);
return;
}
#else
apname[0] = EOS;
#endif
if ((err_log = (char *)malloc(DBENG_PATH_LIMIT)) == (char *)NULL)
{
free(apname);
return;
}
if (dbeng_config_get_log(err_log) != DBENG_OK)
{
free(apname);
free(err_log);
return;
}
if (logman_start(err_log, apname))
{
free(apname);
free(err_log);
return;
}
free(apname);
free(err_log);
}
logman_nf(mess);
if (!islog)
logman_end();
}