/***********************************************************************
* ebase library - an embedded C++ database library *
* Copyright (C) 2001, Jun Sun, jsun@mvista.com or jsun@junsun.net. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
***********************************************************************
*/
#ifndef _ebase_h_
#define _ebase_h_
//////////////////////////////////////////////////////////////////////
// DOCUMENTATION //
//////////////////////////////////////////////////////////////////////
//======================================================================
// LIBRARY ebase_lib
//
// QUICK GUIDE
//
//
// - Data ownership
// Applications exchange data with ebase through data pointers. At any
// time, either the application or ebase owns a piece of data, but never
// both. The ownership of a piece implies that the owner must free
// the memory space occupied by the data if the data is no longer needed
// or when the owner is being deleted.
//
// Data created by applications belong to applications. So are true
// with data created by ebase. The only exceptions are listed as follows :
//
// - When applications call EbRecord::PutFieldxxx(), the applications
// loose the ownership.
//
// - When applications call EbRecord::GetFieldxxxAlloc(), the
// applications own the data pointed by the return pointers.
//
//
//
//
// - More to be added ...
//
//
//
//======================================================================
//////////////////////////////////////////////////////////////////////
// INTERFACE //
//////////////////////////////////////////////////////////////////////
#include "ebglobal.h"
#include "ebarrays.h"
// forward declaration
class Ebase;
class EbaseDef;
class EbRecord;
class DataFile;
class DataDriver;
class IndexDriver;
struct FieldDefinition;
// -*-
// Index Id type. Used to identify an index in an open database.
//
typedef EbUint8 EbIndexId;
// -*-
// Data types supported in Ebase. (To be expanded in the future.)
//
enum EbDataType {
EB_INT32, // EbInt32
EB_STRING, // char *
EB_RAW // void * plus a size parameter
};
// -*-
// Exceptions Return by Ebase functions.
// In this implementation, we use C++ exception mechanism.
//
enum EbErrorEnum {
EBE_FAIL = 3,
EBE_OPEN_FILE = 1,
EBE_OUT_OF_MEMORY = 2,
EBE_OUT_OF_FILE_SPACE = 6,
EBE_DATA_DRIVER_NOT_FOUND = 4,
EBE_FIELD_TYPE_MISMATCH = 7,
EBE_INVALID_FIELD = 8,
EBE_INVALID_INDEX = 9,
EBE_INVALID_RECORD = 10,
EBE_ACCESS_VIOLATION = 11,
EBE_DATABASE_NOT_OPEN = 12,
};
// -*-
// String constants used in ebase
//
extern const char EB_RECORD_ID[]; // "RecordId"
//======================================================================
// CLASS EbError
// EbError is the exception class that is thrown by ebase.
//======================================================================
class EbError {
public:
// -*-
// Constructor.
//
EbError(EbErrorEnum e): _error(e) {}
// -*-
// Return the error number.
//
EbErrorEnum GetError() { return _error; }
// -*-
// Return the error string name.
//
const char* GetStringName();
private:
EbErrorEnum _error;
};
//======================================================================
// CLASS EbaseDef
// EbaseDef is a class that let apps to construct a definition
// used to created Ebase database file. It can also be used to
// query the structure of an existing Ebase database.
//
// IMPORTANT
// Notice that in the current implementation the definition of an
// existing database is not modifiable.
//======================================================================
class EbaseDef : private EbArray {
public:
// -*-
// Constructor.
//
EbaseDef();
// -*-
// Add one field to the definition. This function will make separate
// copy of the fieldName string.
//
// Para :
// [in] fieldName
// The field name.
// [in] dataType
// The data type of the field.
// [in] flag
// Not used for now. It must be 0.
//
void AddField(const char * fieldName,
EbDataType dataType,
EbUint32 flag = 0);
// -*-
// Insert a field at the specified location.
//
// Para :
// [in] pos
// The position at which to insert the new field.
// [in] fieldName
// The field name.
// [in] dataType
// The data type of the field.
// [in] flag
// Not used for now. It must be 0.
//
void InsertField(EbUint32 pos,
const char * fieldName,
EbDataType dataType,
EbUint32 flag = 0);
// -*-
// Report the number of fields in the definition.
//
// Return :
// The number of fields.
//
EbUint32 NumberOfFields();
// -*-
// Get the field name by field index.
//
// Para :
// [in] fieldId
// Must be in the range [0, numFields-1].
//
// Return :
// Pointer to the string that represents the field name.
// Note: Caller needs to copy the string to a separate place
// if it wants to have its own copy.
//
// Exceptions :
// EBE_INVALID_FIELD
//
const char * GetFieldName(EbUint32 fieldId);
// -*-
// Get the field data type.
//
// Para :
// [in] fieldId
// Must be in the range [0, numFields-1].
//
// Return :
// Data type.
//
// Exceptions :
// EBE_INVALID_FIELD
//
EbDataType GetFieldDataType(EbUint32 fieldId);
// -*-
// Get the field flag.
//
// Para :
// [in] fieldId
// Must be in the range [0, numFields-1].
//
// Return :
// field flag.
//
// Exceptions :
// EBE_INVALID_FIELD
//
EbUint32 GetFieldFlag(EbUint32 fieldId);
// -*-
// Find the field index by field name.
//
// Para :
// [in] fieldName
//
// Return :
// The field index of the field. Or < 0 if not found.
//
EbInt32 GetFieldId(const char *fieldName);
// -*-
// Remove all fields
//
void DeleteAll() { EbArray::DeleteAll(); }
private:
friend class Ebase;
// -*-
// Reserve space
//
EbResult ReserveSpace(DataFile &f, EbDataHandle h);
// -*-
// Save
//
void Save(DataFile &f, EbDataHandle h);
// -*-
// Restore
//
EbResult Restore(DataFile &f, EbDataHandle h);
//
// get the field definition
//
FieldDefinition & Get(EbUint32 i);
//
// Copy another def. Not used for now. Kept for the future.
//
void Clone(EbaseDef * def);
//
// whether this instance is modifiable. A definition owned
// by an ebase object is not modifiable.
//
EbBoolean _modifiable;
};
//======================================================================
// CLASS EbRecord
// EbRecord is a class that allows one to retrieve and modify field
// data in a record. It is also used to create a new record.
//
// DESCRIPTION
// EbRecord class provides a bunch of "get field data" functions.
// The caller must make sure the field data type matches
// the appropriate function call. Otherwise exceptions will be
// generated.
//
// EbRecord class provides two flavors of GetField functions :
//
// - The standard GetFeildxxx() will get a pointer to the data
// inside the record (the caller does not own the data). The
// will remina valid as long as the records are not freed.
//
// - The GetFieldxxxAlloc() version wll allocate a new memory space
// and make a copy of the data. The caller owns the copy.
//
//
//
// For some specific data types, a thrid version of get field is provided,
// GetFieldxxxCopy(). This version of get field fucntion will copy the data
// into a pre-allocated buffer. One of such examples is the string data type.
//
// Similarly, EbRecord class also provides two styles of PutField functions :
//
// - The standard PutFieldxxx() version will let ebase take over the
// ownership of the argument data. In other words, the caller will loose
// the ownership of the data, and it should not try to free the data anymore.
// This also implies the argument data must be allocated from heap.
//
// - The PutFieldxxxAlloc() version will let ebase make a (deep) copy of
// the data. The caller remains to be the owner of the argument data.
//
//
//
// Both GetField and PutField functions can be classified into categories :
//
// - The untyped GetField and PutField functions can be applied to
// a field with any data type. The argument data type is a geneic void *
// pointer.
//
// - The typed GetField and PutField functions can only be applied to
// the fields with matching data types. The data type which such a function
// can be applied to is suggested in the function name. Mismatch in
// data types will generate EBE_FIELD_TYPE_MISMATCH exception.
//
//
//
// In each individual GetField and PutField function, the field can be
// identified by either the field name or the field index.
//
// In addition to GetField and PutField, EbRecord provides functions to
// query about field size. For simple data which is represented by
// a byte stream, the field size reflects the number of bytes used
// to store the byte stream.
// For complex data, an option flag is used when querying the field
// size, which has a type-specific meaning.
//
// Field size query functions can be classified into two categories :
// typed and untyped. In both cases, the field can be identified by
// either a field name or a field index.
//======================================================================
class EbRecord {
public:
// -*-
// Destructor.
//
// Notice that there is no public constructor
// for EbRecord becase application is not allowed to create a
// new EbRecord object. Application can only obtain a pointer
// to the EbRecord object through ebase.
//
~EbRecord();
// -*-
// Generic (untyped) getfield by field name
void * GetField(const char * fieldName);
// -*-
// Generic (untypeed) getfield by field name (alloc version)
void * GetFieldAlloc(const char * fieldName);
// -*-
// Generic (untyped) getfield by field index
void * GetField(EbUint32 fieldId);
// -*-
// Generic (untyped) getfield by field index (alloc version)
void * GetFieldAlloc(EbUint32 fieldId);
// -*-
EbInt32 GetFieldInt32(const char *fieldName);
// -*-
EbInt32 GetFieldInt32(EbUint32 fieldId);
// -*-
const char * GetFieldString(const char *fieldName);
// -*-
void GetFieldStringCopy(const char * fieldName, char * buffer);
// -*-
char * GetFieldStringAlloc(const char *fieldName);
// -*-
const char * GetFieldString(EbUint32 fieldId);
// -*-
void GetFieldStringCopy(EbUint32, char * buffer);
// -*-
char * GetFieldStringAlloc(EbUint32 fieldId);
// -*-
// Generic version of querying field size (by field name).
EbUint32 FieldSize(const char *fieldName, EbUint32 option=0);
// -*-
// Generic version of querying field size (by field index).
EbUint32 FieldSize(EbUint32 fieldId, EbUint32 option=0);
// -*-
EbUint32 StringFieldSize(const char *fieldName);
// -*-
EbUint32 StringFieldSize(EbUint32 fieldId);
// -*-
// Generic PutField by field name.
void PutField(const char * fieldName, void * ptr);
// -*-
// Generic PutField by field name (alloc version).
void PutFieldAlloc(const char * fieldName, void * ptr);
// -*-
// Generic PutField by field index.
void PutField(EbUint32 fieldId, void * ptr);
// -*-
// Generic PutField by field index (alloc version).
void PutFieldAlloc(EbUint32 fieldId, void * ptr);
// -*-
void PutFieldInt32(const char *fieldName, EbInt32 number);
// -*-
void PutFieldInt32(EbUint32 fieldId, EbInt32 number);
// -*-
void PutFieldString(const char *fieldName, const char *string);
// -*-
void PutFieldStringAlloc(const char *fieldName, const char *string);
// -*-
void PutFieldString(EbUint32 fieldId, const char *string);
// -*-
void PutFieldStringAlloc(EbUint32 fieldId, const char *string);
// -*-
// Return the number of fields in the database.
//
EbUint32 NumberOfFields();
// -*-
// Return the pointer the database. Each record, no matter which state
// it is in, must belong to some database.
//
Ebase * GetEbase();
private:
friend class Ebase;
friend class IndexDriver;
// -*-
// Constructor. We make the constructor private so that nobody but
// the Ebase object can create a record.
//
EbRecord(Ebase * eb);
//
// All records must be initialized before it is used. Resource allocated
// in Init() will be freed in the destructor.
//
// Return :
// SUCCESS or FAILURE
//
EbResult Init();
//
// CheckDataType. A helper function.
//
// Para :
// [in] fid : field index
// [in] type : data type
//
// Exceptions :
// EBE_INVALID_FIELD
// EBE_FIELD_TYPE_MISMATCH
//
void CheckDataType(EbUint32 fid, EbDataType type);
//
// Locate encoded field.
//
EbUint8* LocateEncodedField(EbUint32 fid);
//
// Get encoded field size.
//
EbUint32 GetEncodedFieldSize(EbUint32 fid);
//
// Decode a field. If the field is already modified or decoded,
// this function does nothing. Otherwise, it will create the
// decoded data from the encoded data.
//
// Exceptions :
// EBE_OUT_OF_MEMORY
//
void DecodeField(EbUint32 fid);
//
// Field class contains field data in decoded form.
//
// Possible states of a field :
// !_decoded && !_changed :
// _decodedData must be NULL;
// PutField will set _changed and _decodedData;
// ReadField will decode and set _decoded;
// CommitRecord will not skip this field and does change it state.
//
// _decoded && !_changed :
// _decodedDatat must be meaningfull. (Could be NULL if NULL is
// a legal value for the data type.)
// PutField will delete current _decodedData, set the new data,
// and set _changed flag;
// ReafField will return _decodedData.
// CommitRecord will not skip this field and does change it state.
//
// _changed :
// _decodedData must be meaningful.
// PutField will replace the current encoded data;
// ReadField will return the _decodedData;
// CommitRecord will encode this field and change state to
// _decoded && !_changed;
//
struct Field {
EbUint8 * _decodedData;
EbBoolean _decoded; // whether this field data is decoded
// if _decoded is FALSE, _decodedData is NULL.
EbBoolean _changed; // whether this field is modifed
// if this field is modified, _decdedData contains new data.
// for a new record, this flag is always set,
// for an exiting record, it is set when this field is modified
// constructor initialize the data
// Memory occupied by a field is freed by the record
Field();
};
//
// an array of fieldds
//
Field *_lField;
//
// pointer to the ebase object.
//
Ebase * _pEbase;
//
// the datahandle that holds the record content
//
EbDataHandle _handle;
//
// pointer to the encoded record.
//
EbUint8 * _pRecordData;
//
// Pointer to next active record. All records of the same ebase are
// linked together.
//
EbRecord * _pNext;
};
//======================================================================
// CLASS EbIndexDef
// EbIndexDef allows applications to construct or query about an index
// definition in Ebase.
// In ebase, an index can be defined based on multiple fields.
// Applications cannot modify the index definition if the definition
// already exists in ebase.
//======================================================================
class EbIndexDef {
public:
// -*-
// Add one field. This function will NOT take over the field name.
//
// It is an error to add a field which already exists in the def.
//
// Para :
// [in] fieldName
// The new field name.
//
// Exceptions :
// [] EBE_INVALID_INDEX
// Too many fields; Or field does not exist.
// [] EBE_ACCESS_VIOLATION
//
void AddField(const char * fieldName);
// -*-
// Set the index flag. A different index flag imply different
// sorting method. By default, the flag is 0.
//
// Para :
// [in] flag
//
void SetIndexFlag(EbUint32 flag) { _pd._flag = flag; }
// -*-
// Number of fields included in the def.
//
// Return :
// Number of fields.
//
EbUint32 NumberOfFields() { return _pd._numFields; }
// -*-
// Get field name. The caller needs to copy the return string to make
// a separate copy.
// Para :
// [in] fieldId
// Must be in the range [0, numFields-1].
//
// Exceptions :
// [] EBE_INVALID_FIELD
// Field index is out of range
//
const char * GetFieldName(EbUint32 fieldIndex);
// -*-
// Get the field id in the ebase def.
//
// Exceptions :
// EBE_INVALID_FIELD
//
EbUint32 GetFieldId(EbUint32 fieldIndex);
// -*-
// Get index flag.
//
EbUint32 GetIndexFlag() { return _pd._flag; }
// -*-
// Check if two index def are equivalent. Two index definitions are
// equivalent if they belong to the same database, have the same flag,
// have the same number of fields and the same fields in exactly the
// same order.
//
EbBoolean Equal(EbIndexDef *def);
private:
friend class Ebase;
friend class EbIndexDefArray;
friend class IndexDriver;
//
// Constructor. We make it private so that one must obtain
// a new one of an existing from an open database.
//
EbIndexDef(Ebase *ebase ) {
_pEbase = ebase;
_pDriver = NULL;
_modifiable = EB_TRUE;
_pd._flag = 0;
_pd._numFields = 0;
}
// simple constructor
EbIndexDef() { EbIndexDef(NULL); }
// clone a copy, return NULL if out of memory
EbIndexDef * Clone();
// run-time variables
EbBoolean _modifiable;
IndexDriver * _pDriver;
Ebase * _pEbase;
// persistent data
struct PD {
EbUint32 _flag;
EbUint32 _numFields;
EbUint8 _fieldId[EB_MAX_NUM_INDEX_FIELDS];
} _pd;
};
//======================================================================
// CLASS Ebase
// The embedded database engine class.
//
// DESCRIPTION
// Ebase class declares an interface for embedded database engine.
// It is embedded because no separate server is around; the function
// is executed through the caller thread. It is a database engine
// because it is a library; it does not provided command line interface.
//
// Ebase provides basic functions for creating database, adding/
// deleting/modifying records, building/deleting indices, and
// searching.
//======================================================================
class Ebase {
public:
// -*-
// Constructor.
//
Ebase();
// -*-
// Destructor.
//
~Ebase();
// -*-
// Create a database with the specified name, fileds, etc.
//
// Note that the caller retains the ownership of 'def' after the call.
//
// Para :
// [in] def
// Database definition.
// [in] dbFileName
// The file used to hold the database
//
static void CreateDatabase(EbaseDef * def,
const char * dbFileName);
// -*-
// Open a database. Almost all functions need an open database
// associated with this object.
//
// Para :
// [in] dbFileName
// Database file name.
//
// Exceptions:
// [] EBE_OPEN_FILE
// [] EBE_OUT_OF_MEMORY
//
void OpenDatabase(const char * dbFileName);
// -*-
// Close database. After closing the current open database, this
// object can open another database.
//
void CloseDatabase();
// -*-
// Query if database is open.
//
EbBoolean IsOpen();
// -*-
// Create a new index template for later index creation. Ebase owns
// the new data. The caller should never try to free the data.
//
// Limit : Currently there can only be one new index def structure
// at any time. The new index def is converted to a regular index
// def whne BuildIndex() is called. The curr new index def is deleted
// if a second NewIndexDef() is called before any BuildIndex() is
// called. The new index def, if there is one, is deleted when database
// is closed.
//
// Exceptions :
// EBE_OUT_OF_MEMORY
//
EbIndexDef * NewIndexDef();
// -*-
// Build a new index. If an index already exists with the same
// definition, this function has no effect other than setting
// the def pointer to the existing index def.
//
// If def was a new index def, the caller will not be able to modify
// the index def strcuture after this function is successfully called.
//
// Para :
// [in/out] def
// Pointer to the index definition.
//
// Exceptions :
// [] EBE_INVALID_INDEX
// The def is not created by this ebase. Or ebase cannot find the
// index driver.
// [] EBE_OUT_OF_MEMORY
// [] EBE_OUT_OF_FILE_SPACE
//
void BuildIndex(EbIndexDef *& def);
// -*-
// Delete an index. The argument can be obtained either through
// NewIndexDef() or through GetIndexDef().
//
// Applications cannot delete the record id index.
//
// Para :
// [in] pIndex
// Pointer to the index def to be deleted.
//
// Exceptions :
// [] EBE_INVALID_INDEX
// The def does not belong to the ebase. Or the index is record
// id index.
//
void DeleteIndex(EbIndexDef * pIndex);
// -*-
// Return the number of indices.
//
EbUint32 NumberOfIndices();
// -*-
// Return a pointer to the existing index def. The ebase owns the data.
//
// Exceptions :
// [] EBE_INVALID_INDEX
//
EbIndexDef * GetIndexDef(EbUint32 iid);
// -*-
// Get index id. Return -1 if not found.
//
EbInt32 GetIndexId(EbIndexDef * pIndex);
// -*-
// Return a new empty record for further manipulation. The new
// will normally be added to database through CommitRecord().
//
// The new record will have -1 record id until it is committed.
//
// The ebase owns the new record. In other words, the caller should
// not try to free the data.
//
// There can be more than one new records at a time.
//
// Exception :
// [] EBE_OUT_OF_MEMORY
//
EbRecord * NewRecord();
// -*-
// Retrieve an existing record by its offset according to the specified
// index sorting order.
//
// The ebase owns the record. In other words, the caller should
// not try to free the data.
//
// Get the same record multiple times will result in multipe copies
// of the same record.
//
// Para :
// [in] offset
// The record offset, [0, numRecords -1 ].
//
// Return :
// Pointer to a newly created record.
//
// Exceptions :
// [] EBE_OUT_OF_MEMORY
// [] EBE_INVALID_INDEX
// [] EBE_INVALID_RECORD_OFFSET
//
EbRecord * GetRecord(EbUint32 offset, EbIndexId iid=0);
// -*-
// Add a new record or modify an existing record, depending on
// whether the record was obtained through NewRecord() or GetRecord().
//
// Para :
// [in] rec
// Pointer to the modified or new record.
//
// Exception :
// [] EBE_OUT_OF_MEMORY
// [] EBE_OUT_OF_FILE_SPACE
//
void CommitRecord(EbRecord *rec);
// -*-
// Delete a record. Both memory resource and file resource are
// freed. For a new, uncommited record, this function frees the
// memory space occupied by the record.
//
// Para :
// [in] pRecord
// The record to be deleted.
//
// Exception :
// [] EBE_INVALID_RECORD
// Possibly record is created by another db.
//
void DeleteRecord(EbRecord *pRecord);
// -*-
// Free the memory occupied by the record. This function is called
// when the caller does not want to use the record anymore. If this
// function is not called on a record, the record will be freed when
// the database is closed.
//
// Exception :
// [] EBE_INVALID_RECORD
// The record is not a valid record of ebase.
//
void FreeRecord(EbRecord * pRecord);
// -*-
// Free the memory occupied by all active records.
//
void FreeAllRecords();
// -*-
// Return the number of records.
//
EbUint32 NumberOfRecords();
// -*-
// Binary search a record. The index must have already been built.
// The record can be a new record, an existing record or a modified
// existing record.
//
// HINT : This search is faster. You only need to supply the
// field data that are relavent to the current index in the
// record. For example, if current index is a dictionary
// order on "LastName" field, you can create a new record and
// put "Smith" in to the "LastName" field to search for a
// record with last name "Smith".
//
// BinarySearch only searches for exact match with built
// indices.
//
// Para :
// [in] index
// The index according to which binary search is performed
// [in] pRecord
// The record
// [out] pos
// The position of the found, matching record.
// [out] found
// whether a match is found.
// [in] option
// Search option in case there is multiple matches :
//
// - < 0 : return the first hit
// - = 0 : return random hit
// - > 0 : return the last hit
//
//
// Exceptions :
// [] EBE_OUT_OF_MEMORY
// [] EBE_INVALID_INDEX
// [] EBE_INVALID_RECORD
//
void BinarySearch(EbIndexDef * index,
EbRecord *pRecord,
EbUint32 & pos,
EbBoolean & found,
EbInt32 option = 0);
// -*-
// Get a pointer to the database definition. The caller must
// not modify the definition.
//
// The caller does not own the ebase def data.
//
// Return :
// a pointer to the copy of the database definition.
// Or NULL on errors.
//
EbaseDef * GetEbaseDef();
private:
friend class EbRecord;
friend class EbIndexDef;
friend class IndexDriver;
//----------------------------------------------------
// private functions
//----------------------------------------------------
//
// Save ebase header to the data file.
//
void SaveHeader();
//
// Save index entries to the data file.
//
void SaveIndexEntries();
//
// Save index definition
//
void SaveIndexDef();
//
// Save ebase definition
//
void SaveEbaseDef();
//
// Add a new record to the database
//
// Exceptions :
// EBE_OUT_OF_MEMORY
// EBE_OUT_OF_FILE_SPACE
//
void AddNewRecord(EbRecord *pRecord);
//
// Modify an existing record.
//
// Exceptions :
// EBE_OUT_OF_MEMORY
//
void ModifyRecord(EbRecord *pRecord);
//
// Get a record by its data handle.
//
// Exceptions :
// EBE_OUT_OF_MEMORY
//
EbRecord * GetRecordByHandle(EbDataHandle handle);
//
// Sort records according to the index def. The records to be sorted
// are put in the handle array. The results are put back in the handle
// array too.
//
EbResult SortRecords(HandleArray *ha, EbIndexDef *idef);
//
// Dump() prints out the important data for debugging purpose
// Implemented in ebase.cpp
//
void Dump();
//----------------------------------------------------
// persistent data
//----------------------------------------------------
// header stores the persistent data structure of the database
// it is stored in 0 handle in the data file
struct EbHeader {
EbUint8 _major;
EbUint8 _minor;
EbUint32 _nextRecordID;
EbUint32 _numRecords;
EbDataHandle _dbDefHandle;
EbDataHandle _indexDefHandle;
EbDataHandle _indexEntryHandle;
} _hdr;
// database definition
EbaseDef _dbDef;
// a list of index definitions
EbIndexDefArray _indexDef;
// index entries,
// _indexEntry is a list of data handle arrays. Each index, as
// defined in _index, has its corresponding data handle array.
// Each element in the array corresponds to the handle of a record.
// The position of that element represents the position of the
// corresponding record in the specified index.
IndexEntryArray _indexEntry;
//----------------------------------------------------
// transient data
//----------------------------------------------------
// pointer to the current new index def
EbIndexDef * _pNewIndexDef;
// the file handle
DataFile * _file;
// an array of pointers to data drivers
DataDriver **_lpDataDriver;
// a list of active records
EbRecord * _pActiveRecord;
};
//////////////////////////////////////////////////////////////////////
// IN-LINE FUNCTIONS //
//////////////////////////////////////////////////////////////////////
// ======================================================================
// IN-LINE FUNCTIONS FOR EbIndexDef
// ======================================================================
inline EbUint32
EbIndexDef::GetFieldId(EbUint32 fieldIndex) {
if (fieldIndex >= _pd._numFields) throw EBE_INVALID_FIELD;
return _pd._fieldId[fieldIndex];
}
inline const char *
EbIndexDef::GetFieldName(EbUint32 fieldIndex)
{
return _pEbase->_dbDef.GetFieldName(GetFieldId(fieldIndex));
}
// ======================================================================
// IN-LINE FUNCTIONS FOR EbRecord
// ======================================================================
inline Ebase *
EbRecord::GetEbase()
{
return _pEbase;
}
inline EbUint32
EbRecord::NumberOfFields()
{
return _pEbase->_dbDef.NumberOfFields();
}
inline void *
EbRecord::GetField(const char * fieldName)
{
return GetField(_pEbase->_dbDef.GetFieldId(fieldName));
}
inline void *
EbRecord::GetFieldAlloc(const char * fieldName)
{
return GetFieldAlloc(_pEbase->_dbDef.GetFieldId(fieldName));
}
inline EbUint32
EbRecord::FieldSize(const char * fieldName, EbUint32 option)
{
return FieldSize(_pEbase->_dbDef.GetFieldId(fieldName), option);
}
inline void
EbRecord::CheckDataType(EbUint32 fid, EbDataType type)
{
if (fid >= NumberOfFields()) {
throw EbError(EBE_INVALID_FIELD);
}
if (_pEbase->_dbDef.GetFieldDataType(fid) != type) {
throw EbError(EBE_FIELD_TYPE_MISMATCH);
}
}
inline EbInt32
EbRecord::GetFieldInt32(EbUint32 fieldId)
{
CheckDataType(fieldId, EB_INT32);
return *(EbInt32*)GetField(fieldId);
}
inline EbInt32
EbRecord::GetFieldInt32(const char *fieldName)
{
return GetFieldInt32((EbUint32)_pEbase->_dbDef.GetFieldId(fieldName));
}
inline const char *
EbRecord::GetFieldString(EbUint32 fieldId)
{
CheckDataType(fieldId, EB_STRING);
return (const char*)GetField(fieldId);
}
inline const char *
EbRecord::GetFieldString(const char *fieldName)
{
return GetFieldString((EbUint32)_pEbase->_dbDef.GetFieldId(fieldName));
}
inline char *
EbRecord::GetFieldStringAlloc(EbUint32 fid)
{
CheckDataType(fid, EB_STRING);
return (char *)GetFieldAlloc(fid);
}
inline char *
EbRecord::GetFieldStringAlloc(const char *fieldName)
{
return GetFieldStringAlloc((EbUint32)_pEbase->_dbDef.GetFieldId(fieldName));
}
inline void
EbRecord::GetFieldStringCopy(EbUint32 fid, char * buffer)
{
strcpy(buffer, GetFieldString(fid));
}
inline void
EbRecord::GetFieldStringCopy(const char * fieldName, char * buffer)
{
GetFieldStringCopy((EbUint32)_pEbase->_dbDef.GetFieldId(fieldName),
buffer);
}
inline EbUint32
EbRecord::StringFieldSize(EbUint32 fid)
{
return FieldSize(fid, 0);
}
inline EbUint32
EbRecord::StringFieldSize(const char *fieldName)
{
return StringFieldSize((EbUint32)_pEbase->_dbDef.GetFieldId(fieldName));
}
inline void
EbRecord::PutField(const char * fieldName, void * ptr)
{
PutField(_pEbase->_dbDef.GetFieldId(fieldName), ptr);
}
inline void
EbRecord::PutFieldAlloc(const char * fieldName, void * ptr)
{
PutFieldAlloc(_pEbase->_dbDef.GetFieldId(fieldName), ptr);
}
inline void
EbRecord::PutFieldInt32(EbUint32 fieldId, EbInt32 number)
{
CheckDataType(fieldId, EB_INT32);
PutFieldAlloc(fieldId, &number);
}
inline void
EbRecord::PutFieldInt32(const char *fieldName, EbInt32 number)
{
PutFieldInt32(_pEbase->_dbDef.GetFieldId(fieldName), number);
}
inline void
EbRecord::PutFieldString(EbUint32 fieldId, const char *string)
{
CheckDataType(fieldId, EB_STRING);
PutField(fieldId, (void*)string);
}
inline void
EbRecord::PutFieldString(const char *fieldName, const char *string)
{
PutFieldString(_pEbase->_dbDef.GetFieldId(fieldName), string);
}
inline void
EbRecord::PutFieldStringAlloc(EbUint32 fieldId, const char *string)
{
CheckDataType(fieldId, EB_STRING);
PutFieldAlloc(fieldId, (void*)string);
}
inline void
EbRecord::PutFieldStringAlloc(const char *fieldName, const char *string)
{
PutFieldStringAlloc(_pEbase->_dbDef.GetFieldId(fieldName), string);
}
// ======================================================================
// IN-LINE FUNCTIONS FOR Ebase
// ======================================================================
inline EbUint32
Ebase::NumberOfIndices()
{
return _indexDef.Size();
}
inline EbUint32
Ebase::NumberOfRecords()
{
return _hdr._numRecords;
}
inline EbInt32
Ebase::GetIndexId(EbIndexDef * pIndex)
{
return _indexDef.FindEqual(pIndex);
}
inline EbBoolean
Ebase::IsOpen()
{
if (_file != NULL) return EB_TRUE;
else return EB_FALSE;
}
#endif