/*********************************************************************** * 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 // // //====================================================================== ////////////////////////////////////////////////////////////////////// // 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 : //
    //
  1. 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. //
  2. //
  3. The GetFieldxxxAlloc() version wll allocate a new memory space // and make a copy of the data. The caller owns the copy. //
  4. //
// // 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 : //
    //
  1. 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. //
  2. //
  3. The PutFieldxxxAlloc() version will let ebase make a (deep) copy of // the data. The caller remains to be the owner of the argument data. //
  4. //
// // Both GetField and PutField functions can be classified into categories : //
    //
  1. 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. //
  2. //
  3. 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. //
  4. //
// // 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 : //
    //
  1. < 0 : return the first hit
  2. //
  3. = 0 : return random hit
  4. //
  5. > 0 : return the last hit
  6. //
// // 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