DataReelDataReelC++ Toolkit Documentation

Database Debug Manager

Contents

Overview
Conditional Directives
Public Data Members
Functions
Database Statistics Functions

Overview

The gxDatabaseDebugManager class is used by applications to troubleshoot and repair damaged or corrupt gxDatabase files. It is derived from the gxDatabase class, so all of the database engine functions are also available. The debug manager adds functions used to open a file without checking its type, analyze the file header, search for valid blocks, and rebuild a damaged file into a new file. The db_debug and ix_debug utility programs are built on this class.

Most debug manager functions write a readable report of what they did into the public status_message string. Print this string after each call to see the results.

The database statistics functions in gxdstats.h are standalone functions used to print detailed information about an open database file to the console. This information is used to analyze and troubleshoot database files. The dbugmgr.h header includes gxdstats.h.

NOTE: BlindOpen() changes the static gxDatabase version, check word, and signature variables used by every gxDatabase object in the program when it opens a version 1, 2, or 3 file. 10/14/2026: Fixed Rebuild() leaving the static signature changed. It now restores the signature, version, and check word before it returns.

Conditional Directives

__CONSOLE__ - The database statistics functions only print output when this directive is defined. Without it, DatabaseStats(), BlockStats(), and both EchoDatabaseVersion() functions do nothing, and the CheckError() functions return their result without printing a message. The Linux build environment (env/linux.env) defines it by default.

Public Data Members

class gxDatabaseDebugManager : public gxDatabase
{
public:
  gxString status_message;
};

The status message is cleared and rewritten by BlindOpen(), AnalyzeHeader(), and Rebuild(). Each line ends with a newline character.

Functions

gxDatabaseDebugManager::AnalyzeHeader()
gxDatabaseDebugManager::BlindOpen()
gxDatabaseDebugManager::BlockSearch()
gxDatabaseDebugManager::CheckFileSize()
gxDatabaseDebugManager::Rebuild()
gxDatabaseDebugManager::ResetFileHeader()
gxDatabaseDebugManager::SetLastKnownRev()
gxDatabaseDebugManager::VerifyBlockHeader()
gxDatabaseDebugManager::VerifyFileHeader()
gxDatabaseDebugManager::VerifyRevLetter()
gxDatabaseDebugManager::VerifyVersion()
gxDatabaseDebugManager::gxDatabaseDebugManager()
gxDatabaseDebugManager::~gxDatabaseDebugManager()

gxDatabaseError gxDatabaseDebugManager::AnalyzeHeader(int test_ver = 1, int test_rev = 1)

Public member function used to check the file header of the open file against the current static gxDatabase signature and version. Calls the overload below with gxDatabase::gxSignature, gxSignatureSize, and gxDatabase::gxVersion.

gxDatabaseError gxDatabaseDebugManager::AnalyzeHeader(const char *sig, int sig_len, FAU ver, int test_ver, int test_rev)

Public member function used to check the file header of the open file and report each step in the status message. The checks are run in this order: the signature (the first "sig_len" minus 1 bytes), the revision letter, the version number, the end of file mark, the heap start, the free space pointer, and the highest block. A "sig_len" larger than the signature size is reduced to the signature size. A bad signature, revision letter, or version number stops the analysis and returns gxDBASE_BAD_HEADER. If "test_rev" is true and the revision letter differs from the revision letter in the last byte of "sig", gxDBASE_REV_MISMATCH is set and a note is added. If "test_ver" is true and the version differs from "ver", gxDBASE_VER_MISMATCH is set and a note is added. The remaining checks set gxDBASE_DBEOF_ERROR, gxDBASE_HEAPSTART_ERROR, gxDBASE_FREESPACE_ERROR, or gxDBASE_HIGHBLOCK_ERROR and continue. The end of file check fails if the recorded end of file is negative or smaller than the actual file size. The heap start check fails if the heap start is inside the file header or past the end of file, or, when the file has blocks, if no valid block header is found at the heap start. The status message ends with "Database file header has errors!" or "Database file header checks good." Returns the first header error found. If there are no errors, returns the last mismatch warning, or zero. NOTE: 10/14/2026: Fixed four problems. The heap start checks tested the highest block pointer in place of the heap start. Later successful reads cleared the error code, so a damaged header could return zero. The revision letter was compared with the library signature in place of "sig", and the version note printed the static version in place of "ver". A "sig_len" larger than the signature size read past the end of the header signature.

gxDatabaseError gxDatabaseDebugManager::BlindOpen(const char *fname, __SBYTE__ last_rev = gxDatabaseRevisionLetter)

Public member function used to open a file in read-only mode without checking the file type. Any file that is already open is closed first. The "last_rev" value is used as the revision letter if a valid one cannot be read from the file. If the file header is valid it is loaded and its revision letter is used. If the header cannot be read or is not valid, the in-memory header is reset with ResetFileHeader() and the open still succeeds. If the file version is below 2000 (version 1 and 2) or below 4000 (version 3), the static gxDatabase version, internal check word, and signature are set to match the file and the detected version and signature are written to the status message. Returns gxDBASE_INVALID_FILE if the file is smaller than a file header, gxDBASE_FILE_OPEN_ERROR if the file cannot be opened or the file name is longer than the name buffer (gxMaxNameLength minus 1 characters), or zero if successful. NOTE: 10/14/2026: Fixed a buffer overflow when the file name was longer than the name buffer.

FAU_t gxDatabaseDebugManager::BlockSearch(FAU_t offset)

Public member function used to find the next valid block header in the open file. The search starts at "offset" and moves forward one byte at a time until gxDatabase::TestBlockHeader() accepts a block header. Returns the file address of the block header, or zero if "offset" is past the end of file, the end of file is reached, or a read fails.

int gxDatabaseDebugManager::CheckFileSize(const char *fname)

Public member function that returns true if the named file is at least as large as a gxFileHeader, or false if it is smaller.

int gxDatabaseDebugManager::Rebuild(const char *fname, int update_ver = 0)

Public member function used to rebuild the open file into a new file named "fname". The new file uses the revision letter of the open file and the current static gxDatabase version. If "update_ver" is true the new file uses the library revision letter (gxDatabaseRevisionLetter) and version (gxDatabaseVersionNumber) instead. The static area size is taken from the file header and the static data is copied. Returns the same value as the full Rebuild() overload.

int gxDatabaseDebugManager::Rebuild(const char *fname, FAU_t *num_objects, FAU ver, __SBYTE__ rev, FAU_t static_area, int copy_static_data)

Public member function used to rebuild the open file into a new file using the current static gxDatabase signature and internal check word, with version "ver" and revision letter "rev". Calls the full overload below.

int gxDatabaseDebugManager::Rebuild(const char *fname, FAU_t *num_objects, const char *sig, int sig_len, FAU ver, __SBYTE__ rev, gxUINT32 check_word, FAU_t static_area, int copy_static_data)

Public member function used to recover every normal block from the open file and write it to a new file named "fname". NOTE: Any existing file with this name is overwritten. The caller must make sure this is safe. The steps are:
1. The old file header is read and its signature and heap start are checked. The signature is compared with the static gxDatabase signature used to read the old file. If the header is good and "static_area" is zero, the static area size is taken from the header.
2. The static gxDatabase signature, version, and check word are set to "sig", "ver", and "check_word" while the new file is written. The old values are used while the old file is read, and all three are restored before the function returns.
3. The new file is created with the static area size and revision letter "rev". If no valid block is found in the old file, an empty file is created and gxDBASE_NOBLOCK_ERROR is set.
4. If "static_area" is not zero and "copy_static_data" is true, the static data is copied to the start of the new file's static area.
5. The old file is walked block by block. Each valid block marked normal has its object data copied into a newly allocated block. Deleted and removed blocks are skipped. A block whose length is shorter than a block header or runs past the end of file is counted as a bad block. When a bad block is found, BlockSearch() is used to find the next valid block. If "rev" is a, b, c, or d (either case) a CRC-32 checksum is written after each object.
The number of objects copied is passed back in "num_objects" if it is not null. The status message lists the results. gxDBASE_BADBLOCK_ERROR is set if bad blocks were found and gxDBASE_BAD_HEADER is set if the old header was damaged. Returns 1 if every block was recovered with no errors, or 0 if the new file could not be created, the old header was damaged, bad blocks were found, or an error occurred while copying (such as a memory allocation, static data, or checksum error). Check the database error code and the status message for details. NOTE: 10/14/2026: Fixed six problems. The function returned 1 even when blocks could not be recovered. The static signature was left set to "sig". A block length of zero looped forever and a short block length caused a huge allocation. Object lengths were cast to int, which truncated lengths over 2GB. The memory allocation checks could never detect a failure. The static data was written at the old file's header size, which put it in the wrong place when the new revision has a different header size.

void gxDatabaseDebugManager::ResetFileHeader(gxFileHeader &fh)

Public member function used to fill "fh" with default values. If the heap start of "fh" is inside the file header (for example zero, from a header that could not be read) it is set to the file header size. The end of file is set to the heap start of "fh", the free space pointer and highest block are set to zero, the signature and version are taken from the static gxDatabase values, and the revision letter is set to the current revision letter. NOTE: 10/14/2026: Fixed the end of file being taken from this object's file header in place of "fh", and a zero heap start giving a negative static area size.

void gxDatabaseDebugManager::SetLastKnownRev(__SBYTE__ last_rev)

Public member function used to set the revision letter this object uses for the open file. Use it when the revision letter stored in a damaged file cannot be trusted.

int gxDatabaseDebugManager::VerifyBlockHeader(const gxBlockHeader &hdr)

Public member function used to make sure "hdr" is a real block header and not object data that happens to contain the check word. Returns true if the check word matches the static gxDatabase internal check word, the status byte is a known block status (bad, deleted, normal, removed, or remote device), and the control byte is valid for that status. Remote device blocks must have a known remote control value. All other blocks must have a control byte of zero. The header is rejected if either unused status byte is non-zero. NOTE: 10/14/2026: Fixed: a header was only rejected when both unused status bytes were non-zero. gxDatabase::TestBlockHeader(), which the rebuild and block search functions use, was changed the same way so the two tests agree. The library never writes these bytes, so every block it created still passes.

int gxDatabaseDebugManager::VerifyFileHeader(const gxFileHeader &fh)

Public member function that returns true if the signature of "fh" (without the revision letter) matches the static gxDatabase signature, the revision letter and version pass VerifyRevLetter() and VerifyVersion(), and the end of file, heap start, and highest block values are not negative.

int gxDatabaseDebugManager::VerifyRevLetter(__SBYTE__ rev)

Public member function that returns true if "rev" is a null character, a space, or one of the letters a through e in either case.

int gxDatabaseDebugManager::VerifyVersion(long ver)

Public member function that returns false if "ver" is less than 1024 or greater than the library version number (gxDatabaseVersionNumber), or true for any version in that range. NOTE: 10/14/2026: Removed an unused list of known version numbers. The gxDatabase engine does not check the version when it opens a file, so only the range is tested.

gxDatabaseDebugManager::gxDatabaseDebugManager()

Default class constructor. Does nothing beyond the gxDatabase base class constructor.

gxDatabaseDebugManager::~gxDatabaseDebugManager()

Class destructor. Does nothing itself. The gxDatabase base class destructor closes the file.

Database Statistics Functions

Standalone functions declared in gxdstats.h and defined in gxdstats.cpp.

BlockStats()
CheckError()
DatabaseStats()
EchoDatabaseVersion()

void BlockStats(gxDatabase *f, FAU oa)

Standalone function used to print the block header and object statistics for the object at address "oa". The object address is the block address plus the block header size. Prints the check word in hexadecimal, the block length, the status character, the next deleted block pointer, and the object length. For revision a, b, c, and d files it also prints the stored and calculated CRC values, or the error message if the checksum cannot be read. For revision c and d files it also prints the record lock header values. "f" must not be null. The console stream format and fill character are restored before the function returns. NOTE: 10/14/2026: Fixed the zero fill character being left set on the console stream.

int CheckError(gxDatabase *f)

Standalone function used to check the last error reported by "f". If an error is set, the database exception message is printed and 1 is returned. Otherwise 0 is returned. "f" must not be null.

int CheckError(gxDatabaseError err)

Standalone function used to check the error code "err". If it is not gxDBASE_NO_ERROR, the matching exception message is printed and 1 is returned. Otherwise 0 is returned.

void DatabaseStats(gxDatabase *f)

Standalone function used to print detailed statistics for the open file "f". The static section shows the file name, signature, revision letter ("Zero" for a null or space revision), version, file header size, block header size, static area size, and file size on disk. The dynamic section shows the open and read/write status, free space, end of file, heap start, highest block, total blocks, normal blocks, and the deleted and removed block counts. For revision d and e files the normal block count is read with NormalBlocks(); for other revisions it is the total blocks minus the deleted and removed blocks. For revision b, c, d, and e files the file lock header values are also printed. The signature string returned by gxDatabase::GetSignature() is freed with delete[] (changed on 10/14/2026; it was freed with a scalar delete). "f" must not be null.

void EchoDatabaseVersion()

Standalone function used to print the default database library version (gxDatabaseVersion) and revision letter (gxDatabaseRevisionLetter). A null or space revision is printed as "Zero". The version is printed in fixed point with 3 digits of precision, and the previous console stream format is restored. NOTE: 10/14/2026: Fixed the fixed point format and precision being left set on the console stream.

void EchoDatabaseVersion(gxDatabase *f)

Standalone function used to print the version and revision letter of the open file "f" with the labels "Database File Version:" and "Database File Revision:". A null or space revision is printed as "Zero". The console stream format is not changed. "f" must not be null. NOTE: 10/14/2026: Fixed the labels. The file values were printed with the "Default Database Library" labels used for the library defaults, and the stream format was changed and not restored.