(*****************************************************************************)
(* MODULE: BSECACHE^                                                         *)
(* RIGHTS: Reggatta Systems, Inc. - COPYRIGHT 1995 - 1999                    *)
(* DESCR.: This module contains the classes for delayed updates              *)
(*****************************************************************************)
Unit BseCache;
{$I BSE.INC}
{$I BAPI.INC}
Interface
Uses
  Classes,

  Windows,
  BDE,
  DBTables,
  DB,

  BseBapi,
  BseColl,
  BseTypes,
  BseTable;

Type
  TCacheCollection =
  Class( TSortedCollection )
    Private
      FTable : TBaseTable;
    Public
      Constructor Create( Table : TBaseTable );
      Function  KeyOf( Item : Pointer ) : Pointer; Override;
      Function  Compare( Key1, Key2 : pointer ) : Integer; Override;
  end;


  TMemTableRecord =
  Class( TBapiListItem )
    Protected
      FRecProps  : RECProps;
      FRecBuff   : Pointer;
      FRecSize   : Word;
      FBookMark  : Pointer;
      FBookSize  : Word;
      FCommitted : Boolean;
      FErrorNum  : DBIResult;
      Function GetUpdateStatus : TUpdateStatus;

    Public
      Constructor Create( P : TObject; Container : TTitanCollection;
                          eLock : DBILockType; pRecBuff, BookMark : Pointer;
                          Size, BookSize : Word );
      Destructor  Destroy; Override;

      Property BookMarkPtr : Pointer
        Read  FBookMark;

      Property Buffer : Pointer
        Read  FRecBuff
        Write FRecBuff;
      Property RecordStatus : Word
        Read  FRecProps.iRecStatus
        Write FRecProps.iRecStatus;

      Property UpdateStatus : TUpdateStatus
        Read GetUpdateStatus;

      Property Deleted : WordBool
        Read  FRecProps.bDeleteFlag
        Write FRecProps.bDeleteFlag;

      Property PhysicalNum : Longint
        Read  FRecProps.iPhyRecNum
        Write FRecProps.iPhyRecNum;

      Property SequenceNum : Longint
        Read  FRecProps.iSeqNum
        Write FRecProps.iSeqNum;

      Property SeqNumChanged : WordBool
        Read  FRecProps.bSeqNumChanged
        Write FRecProps.bSeqNumChanged;
  end;


  TMemTable =
  Class( TBaseTable )
    Protected
      FRecords    : TCacheCollection;
      FRecIndex   : LongInt;
      FCurrRec    : TMemTableRecord;
      FBookSize   : Word;
      FMaster     : TBaseTable;

      Function    FetchRecordFromCache : TMemTableRecord;

    Public
      Constructor Create( P : TObject; Container : TTitanCollection; Name : PChar;
                    iFields, BookSize : Word; Descs : pFLDDesc; Master : TBaseTable );

      Function    GetBookMarkSize : Integer; Override;
      Function    GetBufferSize : Word; Override;

      Procedure   Flush( Flags : TUpdateStatus );
      Procedure   InitTableStruct; Override;
      Procedure   DoneTableStruct; Override;

      Procedure   FirstRecordRaw; Override;
      Procedure   LastRecordRaw ; Override;
      Procedure   NextRecordRaw ; Override;
      Procedure   PrevRecordRaw ; Override;

      Function    IncludeRecordInView( Flags : TUpdateRecordTypes; InCache : Boolean ) : Boolean; Virtual;

      Procedure   GetRecord (                               { Gets the current record }
                    eLock         : DBILockType;            { Optional lock request }
                    pRecBuff      : Pointer;                { Record buffer(client) }
                    pRecProps     : pRECProps               { Optional record properties }
                  ); Override;

      Procedure   InsertRecordSpecial( eLock : DBILockType; pRecBuff, Data : Pointer );
      Procedure   InsertRecord( eLock : DBILockType; pRecBuff : Pointer ); Override;

      Procedure   AppendRecordWithBookMark ( pRecBuff, BookMark, Data : Pointer ); Virtual;
      Procedure   AppendRecord ( pRecBuff : Pointer ); Override;

      Procedure   ModifyRecordWithBookMark( pRecBuff, BookMark, Data : Pointer ); Virtual;
      Procedure   ModifyRecord( pRecBuff : Pointer; bFreeLock : Bool ); Override;

      Procedure   DeleteRecordWithBookMark( pRecBuff, BookMark : Pointer ); Virtual;
      Procedure   DeleteRecord( pRecBuff : Pointer ); Override;

      Procedure   UnDeleteRecord; Override;

      Procedure   LoadProperties( pRecProps : pRECProps ); Override;

      Procedure   GetBookMark( P : Pointer ); Override;
      Procedure   SetToBookmark( P : Pointer ); Override;
      Procedure   GetRecordWithBookMark( P, pRecBuff : Pointer; eLock : dbiLockType ); Override;
      Procedure   CompareBookMarks( pBookMark1, pBookMark2 : Pointer;
                    var CmpBkmkResult : CmpBkmkRslt ); Override;

      Procedure   GetSeqNo (                                { Get logical record number }
                    var iSeqNo    : Longint                 { Pointer to sequence number }
                  ); Override;

      Procedure   SetToSeqNo (                              { Position to a logical record number }
                    iSeqNo        : Longint                 { Sequence number }
                  ); Override;

      Procedure   GetRecordCount( Var iRecCount : Longint ); Override;

      Procedure   PrepareUpdates; Virtual;
      Procedure   CommitUpdates; Virtual;
      Procedure   EmptyTable; Override;         { Deletes all records }

      Procedure   MapGet( Dtype, DSize, DDec, LSize : SmallInt;
                    Src, Dest : Pointer; Var Blank : Bool ); Override;

      Procedure   MapPut( Dtype, DSize, DDec, LSize : SmallInt;
                    Src, Dest : Pointer ); Override;

  end;


  TBaseCacheTable =
  Class( TBaseTable )
    Protected
      FMainCursor    : TBaseTable;
      FCache         : TMemTable;
      FUpdateInfo    : TUpdateRecordTypes;
      FGetOldRec     : Boolean;
      FWorkBookMark  : Pointer;

    Protected
      Function    GetTableName : PChar; Override;
      Procedure   SetTableName( P : PChar ); Override;
      Function    GetFileName : PChar; Override;
      Procedure   SetFileName( P : PChar ); Override;


    Public
      Property Cache : TMemTable
        Read  FCache;
      Property MainCursor : TBaseTable
        Read  FMainCursor;

      Constructor Create( Main : TBaseTable );
      Destructor  Destroy; Override;

      Function    GetBufferSize : Word; Override;
      Function    GetBookMarkSize : Integer; Override;
      Procedure   GetFieldFromOffset( Offset, Size : Integer; pFDesc : pFLDDesc ); Override;
      Function    GetSearchAction( bKeyIncl, bNext : Boolean ) : TCmpType; Override;

      Procedure   InitTableStruct; Override;
      Procedure   DoneTableStruct; Override;

      Procedure   FirstRecordRaw; Override;
      Procedure   LastRecordRaw ; Override;
      Procedure   NextRecordRaw ; Override;
      Procedure   PrevRecordRaw ; Override;

      Procedure   TranslateGet(
                    P             : TFieldCacheItem;        { Field Description Info }
                    pRecBuff      : Pointer;                { Record buffer }
                    pDest         : Pointer;                { Destination field buffer }
                    var bBlank    : Bool                    { Returned : is field blank }
                  ); Override;

      Procedure   TranslatePut(
                    P             : TFieldCacheItem;        { Field Description Info }
                    pRecBuff      : Pointer;                { Record buffer }
                    pSrc          : Pointer                 { Source field buffer }
                  ); Override;

      Procedure   LoadDriverHeader; Override;

      Procedure   GetFieldCount( Var Fields, RecSize : Word ); Override;

      Procedure   OpenTable; Override;
      Procedure   CloseTable; Override;

      Procedure   Clone( bReadOnly : Bool; bUniDirectional : Bool;
                          var hCurNew : hDBICur ); Override;

      Procedure   OpenIndex (                               { Open an index }
                    pszIndexName  : PChar;                  { Index Name }
                    iIndexId      : Word                    { Index number (if applicable) }
                  ); Override;

      Procedure   CloseIndex (                              { Close an index }
                    pszIndexName  : PChar;                  { Index Name }
                    iIndexId      : Word                    { Index number (if applicable) }
                  ); Override;

      Procedure   GetNativeDesc( iField : Integer; Src : Pointer; P : pFldDesc;
                    Var LocType, LocSize : Word ); Override;

      Procedure   GetFieldDescs( pFDesc : pFLDDesc ); Override;

      Procedure   SetToBegin; Override;
      Procedure   SetToEnd  ; Override;

      Procedure   GetBookMark( P : Pointer ); Override;
      Procedure   SetToBookmark( P : Pointer ); Override;
      Procedure   GetRecordWithBookMark( P, pRecBuff : Pointer; eLock : dbiLockType ); Override;
      Procedure   CompareBookMarks( pBookMark1, pBookMark2 : Pointer;
                    var CmpBkmkResult : CmpBkmkRslt ); Override;
      Function    ShowRecordInCache( pRecBuff : Pointer; pProps : pRECProps ) : Boolean; Virtual;

      Procedure   FirstRecord   ; Override;
      Procedure   LastRecord    ; Override;

      Procedure   LoadProperties( pRecProps : pRECProps ); Override;

      Procedure   GetNextRecord (                           { Find/Get the next record }
                    eLock         : DBILockType;            { Optional lock request }
                    pRecBuff      : Pointer;                { Record buffer(client) }
                    pRecProps     : pRECProps               { Optional record properties }
                  ); Override;

      Procedure   GetPriorRecord (                          { Find/Get the prior record }
                    eLock         : DBILockType;            { Optional lock request }
                    pRecBuff      : Pointer;                { Record buffer(client) }
                    pRecProps     : pRECProps               { Optional record properties }
                  ); Override;

      Procedure   GetRecord (                               { Gets the current record }
                    eLock         : DBILockType;            { Optional lock request }
                    pRecBuff      : Pointer;                { Record buffer(client) }
                    pRecProps     : pRECProps               { Optional record properties }
                  ); Override;

      Procedure   GetRecordForKey (
                    bDirectKey : Bool;
                    iFields, iLen : Word; 
                    pKey, pRecBuff : Pointer 
                  ); Override;

      Procedure   GetVchkDesc (                             { Get valcheck descriptor }
                    iValSeqNo     : Word;                   { Valcheck sequence number }
                    pvalDesc      : pVCHKDesc               { Returned valcheck description }
                  ); Override;

      Procedure   GetRintDesc (                             { Get referential integrity descriptor }
                    iRintSeqNo    : Word;                   { Rint sequence number }
                    printDesc     : pRINTDesc               { Returned rint description }
                  ); Override;

      Procedure   AcqTableLock (                            { Lock a table }
                    eLockType     : DBILockType             { Lock type }
                  ); Override;

      Procedure   RelTableLock (                            { Unlocks Table level locks }
                    bAll          : Bool;                   { True for all table level locks }
                    eLockType     : DBILockType             { Specific lock type }
                  ); Override; 

      Procedure   RelRecordLock (                           { Releases record level locks }
                    bAll          : Bool                    { True for all. Default Current. }
                  ); Override;

      Procedure   IsRecordLocked (                          { Check if current record is locked }
                    var bLocked   : Bool                    { Rec lock status }
                  ); Override; 

      Procedure   IsTableLocked (                           { Verify if Table is locked }
                    epdxLock      : DBILockType;            { Lock type to verify }
                    var iLocks    : Word                    { Nbr of locks of the given type }
                  ); Override;

      Procedure   IsTableShared (                           { Verify if this is a shared table }
                    var bShared   : Bool                    { Shared status }
                  ); Override;

      Procedure   InitRecord( pRecBuff : Pointer ); Override;
      Procedure   InsertRecord( eLock : DBILockType; pRecBuff : Pointer ); Override; 
      Procedure   AppendRecord ( pRecBuff : Pointer ); Override;
      Procedure   ModifyRecord( pRecBuff : Pointer; bFreeLock : Bool ); Override;
      Procedure   DeleteRecord( pRecBuff : Pointer ); Override;
      Procedure   UnDeleteRecord; Override;

      Procedure   ReadBlock ( Var iRecords : Longint; pBuf : Pointer ); Override;
      Procedure   WriteBlock ( Var iRecords : Longint; pBuf : Pointer ); Override;

      Procedure   GetSeqNo (                                { Get logical record number }
                    var iSeqNo    : Longint                 { Pointer to sequence number }
                  ); Override;

      Procedure   SetToSeqNo (                              { Position to a logical record number }
                    iSeqNo        : Longint                 { Sequence number }
                  ); Override;

      Procedure   GetCursorProps( var curProps : CURProps ); Override;
      Procedure   GetRecordCount( Var iRecCount : Longint ); Override;
      Procedure   GetExactRecordCount( Var iRecCount : Longint ); Override;
      Procedure   SetToRecordNo (                           { Position to Physical Rec# }
                    iRecNo        : Longint                 { Physical record number }
                  ); Override;

      Procedure   SaveChanges; Override;                    { flush all buffered changes }
      Procedure   ForceReread; Override;                    { reread buffered record }
      Procedure   ForceRecordReread (                       { Force Reread of current record from Server }
                    pRecBuff      : Pointer                 { Returned : record buffer }
                  ); Override;
      Procedure   OpenLockList (                            { Get a list of locks }
                    bAllUsers     : Bool;                   { True, for all Users locks }
                    bAllLockTypes : Bool;                   { True, for all lock types }
                    var hLocks    : hDBICur                 { Returned cursor on Lock list }
                  ); Override;

      Procedure   MakePermanent (                           { Make temporary table permanent }
                    pszName       : PChar;                  { Rename temporary table }
                    bOverWrite    : Bool                    { Overwrite existing file }
                  ); Override;

      Procedure   SetRange (                                { Set cursor to a range }
                    bKeyItself    : Bool;                   { Whether Key or Record buffer }
                    iFields1      : Word;                   { Key fields to be mathced in full }
                    iLen1         : Word;                   { Key length to compare }
                    pKey1         : Pointer;                { Top/Left key in Range }
                    bKey1Incl     : Bool;                   { If Inclusive of Key1 }
                    iFields2      : Word;                   { Key fields to be mathced in full }
                    iLen2         : Word;                   { Key length to compare }
                    pKey2         : Pointer;                { Bottom/Right key in Range }
                    bKey2Incl     : Bool                    { If Inclusive of Key2 }
                  ); Override;

      Procedure   ResetRange; Override;

      Procedure   CompareKeys (                             { Compare two keys }
                    pKey1         : Pointer;                { Key buffer 1 to compare }
                    pKey2         : Pointer;                { Key buffer 2 (Or NULL) }
                    iFields       : Word;                   { Fields to compare in full }
                    iLen          : Word;                   { Partial key to compare }
                    var iResult   : SmallInt                { Compare result }
                  ); Override;

      Procedure   SwitchToIndex(
                    pszIndexName  : PChar;
                    pszTagName    : PChar;
                    iIndexId      : Word;
                    bCurrRec      : Bool
                  ); Override; 

      Procedure   SetToKey (                                { Set key condition }
                    eSearchCond   : DBISearchCond;          { Search condition (default is =) }
                    bDirectKey    : Bool;                   { Key is supplied directly }
                    iFields       : Word;                   { No of full fields to match }
                    iLen          : Word;                   { Partial key len of last field }
                    pBuff         : Pointer                 { Either Record buffer or Key itself }
                  ); Override;

      Procedure   SetToKeySpecial(                          { Set key condition }
                    Action        : TCmpType;               { Search condition (default is =) }
                    bDirectKey    : Bool;                   { Key is supplied directly }
                    iFields       : Word;                   { No of full fields to match }
                    iLen          : Word;                   { Partial key len of last field }
                    pBuff         : Pointer;                { Either Record buffer or Key itself }
                    pRetBuff      : Pointer                 { Return Buffer }
                  ); Override;

      Procedure   ExtractKey (                              { Get the key value of current record }
                    pRecBuf       : Pointer;                { Record buffer (optional) }
                    pKeyBuf       : Pointer                 { Returned. Key bytes. }
                  ); Override;

      Procedure   ExtractKeyPrecise(                        { Get the key value of current record }
                    pRecBuf       : Pointer;                { Record buffer (optional) }
                    pKeyBuf       : Pointer;                { Returned. Key bytes. }
                    iFields       : word;                   { # of Fields or 0 }
                    iLen          : word;                   { len of last field }
                    var iKeyLen   : word
                  ); Override; 

      Procedure   GetIndexDesc (                            { Get index properties }
                    iIndexSeqNo   : Word;                   { Index number }
                    var idxDesc   : IDXDesc                 { Returned index description }
                  ); Override;
      Procedure   GetIndexDescs (                           { Get index properties }
                    idxDesc   : PIDXDesc                    { Returned index description }
                  ); Override;
      Procedure   GetIndexForField(                         { Get index properties }
                    iFld          : Word;                   { Field Number (1..N) }
                    bProdTagOnly  : Bool;                   { If TRUE, only xBASE prod tags will be returned }
                    var   idxDesc : IDXDesc                 { Returned index description }
                  ); Override;

      Procedure   GetIndexSeqNo (                           { Get index sequence number }
                    pszIndexName  : PChar;                  { Index name }
                    pszTagName    : PChar;                  { Tag name (if applicable) }
                    iIndexId      : Word;                   { Index number }
                    var iIndexSeqNo  : Word                 { Index number }
                  ); Override;

      Procedure   EmptyTable; Override;         { Deletes all records }

      Procedure   AddIndex (                                { Add a new index }
                    var IdxDesc   : IDXDesc;                { Description of the index }
                    pszKeyviolName : PChar                  { Keyviol table name (optional) }
                  ); Override;

      Procedure   DeleteIndex (                             { Delete index }
                    pszIndexName  : PChar;                  { Index name }
                    pszIndexTagName : PChar;                { Index tagname (xbase MDX) }
                    iIndexId      : Word                    { Index number }
                  ); Override;

      Procedure   BeginDelayedUpdates (                     { put cursor in delayed update mode }
                    var hCursor   : hDBICur                 { In/Out : returns new Cursor }
                  ); Override;

      Procedure   EndDelayedUpdates (                       { Convert cursor back to normal cursor }
                    var hCursor   : hDBICur                 { In/Out : returns original Cursor }
                  ); Override;

      Procedure   ApplyDelayedUpdates (                     { Perform the specified operation. }
                    eUpdCmd       : DBIDelayedUpdCmd        { Op Type: Commit or Rollback. }
                  ); Override;

      Procedure   GetDelayedUpdates (
                    var hCache    : hDBICur                 { In/Out: returns cursor on cache }
                  ); Override;

      Procedure   LockRecord( eLock : DBILockType ); Override;

      Procedure   GetLdObj (                                { Get language driver }
                    var   pLdObj  : Pointer                 { Returned language driver object }
                  ); Override;

      Procedure   OpenBlob (                                { Open a blob for access }
                    pRecBuf       : Pointer;                { Record Buffer }
                    iField        : Word;                   { Field number (1..n) }
                    eOpenMode     : DBIOpenMode             { Open for Read or RW }
                  ); Override;

      Procedure   GetBlobSize (                             { Get Blob Size }
                    pRecBuf       : Pointer;                { Record Buffer }
                    iField        : Word;                   { Field number (1..n) }
                    var iSize     : Longint                 { returned size }
                  ); Override;

      Procedure   GetBlob (                                 { Read bytes from blob }
                    pRecBuf       : Pointer;                { Record Buffer }
                    iField        : Word;                   { Field number of blob (1..n) }
                    iOffSet       : Longint;                { Starting position   }
                    iLen          : Longint;                { No of bytes to be read   }
                    pDest         : Pointer;                { Destination }
                    var iRead     : Longint                 { Actual no of bytes read }
                  ); Override;

      Procedure   PutBlob (                                 { Write bytes to blob }
                    pRecBuf       : Pointer;                { Record Buffer }
                    iField        : Word;                   { Field number of blob (1..n) }
                    iOffSet       : Longint;                { Starting position   }
                    iLen          : Longint;                { No of bytes to put   }
                    pSrc          : Pointer                 { pntr to Source }
                  ); Override;

      Procedure   TruncateBlob (                            { Reduces the blob size }
                    pRecBuf       : Pointer;                { Record Buffer }
                    iField        : Word;                   { Field number of blob (1..n) }
                    iLen          : Longint                 { New blob length }
                  ); Override;

      Procedure   FreeBlob (                                { Free the blob }
                    pRecBuf       : Pointer;                { Record Buffer }
                    iField        : Word                    { Field number of blob (1..n) }
                  ); Override;

      Procedure   GetBlobHeading (                          { Get Blob Heading }
                    iField        : Word;                   { Field number of blob (1..n) }
                    pRecBuf       : Pointer;                { Record buffer of owner record }
                    pDest         : Pointer                 { Destination buffer }
                  ); Override;

      Procedure   SetFieldMap (                             { Set a fieldmap }
                    iFields       : Word;                   { Number of fields }
                    pFldDesc      : pFLDDesc                { Array of field descriptions }
                  ); Override;

      Procedure   GetField(                                 { Get Field value }
                    iField        : Word;                   { Field # (1..n) }
                    pRecBuff      : Pointer;                { Record buffer }
                    pDest         : Pointer;                { Destination field buffer }
                    var bBlank    : Bool                    { Returned : is field blank }
                  ); Override;

      Procedure   PutField (                                { Put a value in the record buffer }
                    iField        : Word;                   { Field # (1..n) }
                    pRecBuff      : Pointer;                { Record buffer }
                    pSrc          : Pointer                 { Source field buffer }
                  ); Override;

      Procedure   VerifyField (                             { Verifies the field value }
                    iField        : Word;                   { Field # (1..n) }
                    pSrc          : Pointer;                { Field Value }
                    var bBlank    : Bool                    { Field is Blank (Returned) }
                  ); Override;

      Procedure   AddFilter (                               { Add a filter to the cursor }
                    iClientData   : Longint;                { Client supplied data      (opt) }
                    iPriority     : Word;                   { 1..N with 1 being highest (opt) }
                    bCanAbort     : Bool;                   { TRUE if pfFiltercan return ABORT (opt) }
                    pcanExpr      : pCANExpr;               { Expression tree        (opt) }
                    pfFilter      : pfGENFilter;            { ptr to filter function (opt) }
                    var hFilter   : hDBIFilter              { Returns filter handle }
                  ); Override;

      Procedure   DropFilter (                              { Drop a filter }
                    hFilter       : hDBIFilter              { Filter handle }
                  ); Override;

      Procedure   ActivateFilter (                          { Activate a Filter }
                    hFilter       : hDBIFilter              { Filter handle }
                  ); Override;

      Procedure   DeactivateFilter (                        { Deactivate Filter }
                    hFilter       : hDBIFilter              { Filter handle }
                  ); Override;

      Procedure   GetFilterInfo (                           { Get filter information }
                    hFilter       : hDBIFilter;             { Filter handle          /NULL }
                    iFilterId     : Word;                   { Filter id              /0 }
                    iFilterSeqNo  : Word;                   { Filter sequence number /0 }
                    var Filterinfo : FilterInfo             { Returns filter info }
                  ); Override;
      Procedure   GetProp (                                 { Get property }
                    iProp         : Longint;                { Property to retrieve }
                    PropValue     : Pointer;                { == NULL, validate iProp for getting }
                    iMaxLen       : Word;                   { Length of buffer pPropValue }
                    var   iLen    : Word                    { Returns required length }
                  ); Override;

      Procedure   SetProp (                                 { Get property }
                    iProp         : Longint;                { Property to retrieve }
                    PropValue     : Longint                 { == NULL, validate iProp for getting }
                  ); Override;

      Procedure   ValidateProp (                            { Validate a property }
                    iProp         : Longint;                { property to validate }
                    bSetting      : Bool                    { TRUE:setting, FALSE:getting }
                  ); Override;

 end;


Implementation
Uses

  Forms,
  SysUtils,


  BseConst,
  BseUtils,
  BseDbase,
  BseFilt,
  BseErrs;


Constructor TCacheCollection.Create( Table : TBaseTable );
begin
  Inherited Create;
  FTable := Table;
end;


Function TCacheCollection.KeyOf( Item : pointer ) : pointer;
begin
  Result := TMemTableRecord( Item ).FBookMark;
end;


Function TCacheCollection.Compare( Key1, Key2 : Pointer ) : Integer;
var
  i : CmpBkmkRslt;
begin
  Try
    FTable.CompareBookMarks( Key1, Key2, i );
    Result := Integer( i );
  Except
    On E:ETitanEngineError Do
      Result := 1;
  end;
end;


Constructor TMemTableRecord.Create( P : TObject; Container : TTitanCollection;
                                    eLock : DBILockType; pRecBuff, BookMark : Pointer;
                                    Size, BookSize : Word );
begin
  FBookSize := BookSize;
  if ( BookSize > 0 ) then
  begin
    FBookMark := AllocMem( BookSize );
    if ( FBookMark <> NIL ) then
    begin
      if ( BookMark <> NIL ) then
        Move( BookMark^, FBookMark^, FBookSize )
      else
        if ( Container <> NIL ) then
          LongInt( FBookMark^ ) := Succ( Container.Count )
        else
          LongInt( FBookMark^ ) := 1;
    end;
  end;
  Inherited Create( P, Container );
  FRecSize := Size;
  if ( Size > 0 ) and ( pRecBuff <> NIL ) then
  begin
    GetMem( FRecBuff, FRecSize );
    if ( FRecBuff <> NIL ) then
      Move( pRecBuff^, FRecBuff^, FRecSize );
  end;
  If ( Container <> NIL ) then
    PhysicalNum := Container.Count;
end;


Destructor TMemTableRecord.Destroy;
begin
  If ( FRecBuff <> NIL ) then
    FreeMem( FRecBuff, FRecSize );
  If ( FBookMark <> NIL ) then
    FreeMem( FBookMark, FBookSize );
  Inherited Destroy;
end;


Function TMemTableRecord.GetUpdateStatus : TUpdateStatus;
begin
  Result := TUpdateStatus( RecordStatus );
end;


Constructor TMemTable.Create( P : TObject; Container : TTitanCollection; Name : PChar;
              iFields, BookSize : Word; Descs : pFLDDesc; Master : TBaseTable );
var
  i,j    : Word;
  M      : PDescArray;
  Desc   : pFLDDesc;
  OffSet : Word;

  Procedure CalcFieldLength( Var Desc : FLDDesc );
  begin
    With Desc do
    begin
      If ( iLen = 0 ) then
      begin
        case iFldType of
          fldZSTRING:
            iLen := Succ( iUnits1 );
          fldDATE,
          fldTIME,
          fldTIMESTAMP:
            iLen := Sizeof( TTimeStamp );
          fldBOOL,
          fldINT16,
          fldUINT16:
            iLen := SizeOf( SmallInt );
          fldINT32,
          fldUINT32:
            iLen := SizeOf( LongInt );
          fldFLOAT:
            iLen := SizeOf( Double );
          fldBCD:
            iLen := Abs( iUnits2 );
          fldFLOATIEEE:
            iLen := SizeOf( Extended );
        else
          iLen := iUnits1;
        end;
      end;
    end;
  end;

begin
  Inherited Create( P, Container, Name, NIL, 0, dbiREADWRITE, dbiOPENSHARED );
  FBookSize := BookSize;
  OffSet := 0;
  M := PDescArray( Descs );
  For i := 1 to iFields do
  begin
    Desc := @M^[ Pred( i ) ];
    CalcFieldLength( Desc^ );
    Desc^.iOffset := Offset;
    Inc( Offset, Desc^.iLen );
    TFieldCacheItem.CreateField( FFieldDescs, Desc, i, 0, 0 );
  end;
  GetFieldCount( i, j );
  FMaster := Master;
end;


Function TMemTable.GetBufferSize : Word;
begin
  Result := FRecSize;
end;


Function TMemTable.GetBookMarkSize : Integer;
begin
  If ( FBookSize <> 0 ) then
    Result := FBookSize
  else
    Result := SizeOf( LongInt );
end;


Procedure TMemTable.Flush( Flags : TUpdateStatus );
var
  I : Integer;
  P : TMemTableRecord;
begin
  For i := Pred( FRecords.Count ) DownTo 0 do
  begin
    P := TMemTableRecord( FRecords.Items[ i ] );
    if ( P.UpdateStatus = Flags ) then
      P.Free;
  end;
end;


Procedure TMemTable.InitTableStruct;
begin
  FRecords := TCacheCollection.Create( Self );
end;


Procedure TMemTable.DoneTableStruct;
begin
  FRecords.Free;
end;


Procedure TMemTable.FirstRecordRaw;
begin
  If ( FRecords.Count > 0 ) then
  begin
    FRecIndex := 1;
    GetRecord( dbiNOLOCK, DriverBuffer, NIL );
  end
  else
    ThrowEOFException;
end;


Procedure TMemTable.LastRecordRaw;
begin
  If ( FRecords.Count > 0 ) then
  begin
    FRecIndex := FRecords.Count;
    GetRecord( dbiNOLOCK, DriverBuffer, NIL );
    Exit;
  end;
  ThrowBOFException;
end;


Procedure TMemTable.NextRecordRaw;
begin
  If ( FRecIndex < FRecords.Count ) then
  begin
    Inc( FRecIndex );
    Try
      GetRecord( dbiNOLOCK, DriverBuffer, NIL );
      Exit;
    Except
    end;
  end;
  ThrowEOFException;
end;


Procedure TMemTable.PrevRecordRaw;
begin
  If ( FRecIndex > 1 ) then
  begin
    Dec( FRecIndex );
    Try
      GetRecord( dbiNOLOCK, DriverBuffer, NIL );
      Exit;
    Except
    end;
  end;
  ThrowBOFException;
end;


Function TMemTable.IncludeRecordInView( Flags : TUpdateRecordTypes; InCache : Boolean ) : Boolean;
begin
  if InCache then
  begin
    Case FCurrRec.UpdateStatus of
      usModified:
        Result := ( rtModified in Flags );
      usInserted:
        Result := ( rtInserted in Flags );
      usDeleted:
        Result := ( rtDeleted  in Flags );
    else
      Result := TRUE;
    end;
  end
  else
    Result := ( rtUnModified in Flags );
end;


Procedure TMemTable.GetRecord (                             { Gets the current record }
           eLock         : DBILockType;                     { Optional lock request }
           pRecBuff      : Pointer;                         { Record buffer(client) }
           pRecProps     : pRECProps                        { Optional record properties }
         );
begin
  if ( FRecords.Count > 0 ) then
  begin
    If ( FRecIndex <= 0 ) then
      FRecIndex := 1
    else
      If ( FRecIndex > FRecords.Count ) then
        ThrowEOFException;
    FCurrRec := TMemTableRecord( FRecords.Items[ Pred( FRecIndex ) ] );
    if ( FCurrRec <> NIL ) then
    begin
      if ( pRecBuff <> NIL ) then
        Move( FCurrRec.Buffer^, pRecBuff^, FCurrRec.FRecSize );
      LoadProperties( pRecProps );
      UpdateTableState;
      Exit;
    end;
    ThrowException( DBIERR_NOCURRREC );
  end;
  ThrowEOFException;
end;


Procedure TMemTable.LoadProperties( pRecProps : pRECProps );
begin
  If ( FCurrRec <> NIL ) and ( pRecProps <> NIL ) then
    Move( FCurrRec.FRecProps, pRecProps^, Sizeof( RECProps ) );
end;


Procedure TMemTable.GetBookMark( P : Pointer );
begin
  if ( FCurrRec.FBookMark <> NIL ) then
  begin
    Move( FCurrRec.FBookMark^, P^, BookMarkSize );
    Exit;
  end;
  ThrowException( DBIERR_NOCURRREC );
end;


Procedure TMemTable.SetToBookmark( P : Pointer );
var
  C : CmpBkmkRslt;
  i : Longint;
begin
  If ( FRecords.Count > 0 ) then
  begin
    For i := 0 to Pred( FRecords.Count ) do
    begin
      FCurrRec  := TMemTableRecord( FRecords.Items[ i ] );
      FRecIndex := Succ( i );
      If ( FCurrRec.UpdateStatus <> usInserted ) then
      begin
        CompareBookMarks( P, FCurrRec.FBookMark, C );
        If ( C = cmpEQL ) then
          Exit;
      end;
    end;
  end;
  ThrowEOFException;
end;


Procedure TMemTable.GetRecordWithBookMark( P, pRecBuff : Pointer; eLock : dbiLockType );
begin
  SetToBookMark( P );
end;


Procedure TMemTable.CompareBookMarks( pBookMark1, pBookMark2 : Pointer;
           var CmpBkmkResult : CmpBkmkRslt );
begin
  If ( FMaster <> NIL ) then
    FMaster.CompareBookMarks( pBookMark1, pBookMark2, CmpBkmkResult )
  else
  begin
    { Bookmarks are simply LongInts }
    If ( LongInt( pBookMark1^ ) < LongInt( pBookMark2^ ) ) then
      CmpBkMkResult := CMPLess
    else
      If ( LongInt( pBookMark1^ ) > LongInt( pBookMark2^ ) ) then
       CmpBkMkResult := CMPGtr
      else
        CmpBkMkResult := CMPEql;
  end;
end;


Procedure TMemTable.GetRecordCount( Var iRecCount : Longint );
begin
  iRecCount := LongInt( FRecords.Count );
end;


Function TMemTable.FetchRecordFromCache : TMemTableRecord;
begin
  if ( FRecords.Count > 0 ) then
    Result := TMemTableRecord( FRecords.Items[ Pred( FRecIndex ) ] )
  else
    Result := NIL;
end;


Procedure TMemTable.GetSeqNo (                              { Get logical record number }
           var iSeqNo    : Longint                          { Pointer to sequence number }
         );
begin
  FCurrRec := TMemTableRecord( FRecords.Items[ Pred( FRecIndex ) ] );
  If ( FCurrRec <> NIL ) then
  begin
    iSeqNo := FCurrRec.SequenceNum;
    Exit;
  end;
  ThrowException( DBIERR_NOCURRREC );
end;


Procedure TMemTable.SetToSeqNo (                             { Position to a logical record number }
           iSeqNo        : Longint                          { Sequence number }
         );
Var
  i : LongInt;
begin
  For i := 0 to Pred( FRecords.Count ) do
  begin
    FCurrRec := FRecords.Items[ i ];
    If ( FCurrRec.SequenceNum = iSeqNo ) then
    begin
      FRecIndex := Succ( i );
      Exit;
    end;
  end;
  ThrowEOFException;
end;


Procedure TMemTable.InsertRecordSpecial( eLock : DBILockType; pRecBuff, data : Pointer );
var
  T    : TMemTableRecord;
  Coll : TTitanCollection;
  bm   : Longint;
begin
  ValidateParameter( pRecBuff );
  If ( FRecords.Count > 0 ) and ( FRecIndex > 0 ) then
    Coll := NIL
  else
    Coll := FRecords;
  T := TMemTableRecord.Create( Self, Coll, elock, pRecBuff, NIL, FRecSize, BookMarkSize );
  If ( Coll = NIL ) then
  begin
    FRecords.AtInsert( Pred( FRecIndex ), T );
    T.Container := FRecords;
    If ( FMaster = NIL ) then {We need to set the bookmark}
    begin
      bm := FRecords.Count;
      Move( bm, T.BookMarkPtr^, SizeOf( LongInt ) );
    end;
  end;
  T.RecordStatus := Word( usInserted );
end;


Procedure TMemTable.InsertRecord( eLock : DBILockType; pRecBuff : Pointer );
begin
  InsertRecordSpecial( eLock, pRecBuff, NIL );
end;


Procedure TMemTable.ModifyRecordWithBookMark( pRecBuff, BookMark, Data : Pointer );
var
  IsUpdate : Boolean;
begin
  IsUpdate := TRUE;
  If ( BookMark <> NIL ) then
  begin
    Try
      SetToBookMark( BookMark );
    Except
      On E:ETitanEngineError do
      begin
        AppendRecordWithBookMark( pRecBuff, BookMark, Data );
        IsUpdate := FALSE;
        SetToBookMark( BookMark );
      end;
    end;
  end;
  If IsUpdate and ( pRecBuff <> NIL ) then
    Move( pRecBuff^, FCurrRec.Buffer^, FRecSize );
  FCurrRec.RecordStatus := Word( usModified );
end;


Procedure TMemTable.ModifyRecord( pRecBuff : Pointer; bFreeLock : Bool );
begin
  ModifyRecordWithBookMark( pRecBuff, NIL, NIL );
end;


Procedure TMemTable.DeleteRecordWithBookMark( pRecBuff, BookMark : Pointer );
begin
  If ( BookMark <> NIL ) then
  begin
    Try
      SetToBookMark( BookMark );
    Except
      On E:ETitanEngineError do
      begin
        AppendRecordWithBookMark( pRecBuff, BookMark, NIL );
        SetToBookMark( BookMark );
      end;
    end
  end;
  FCurrRec.RecordStatus := Word( usDeleted );
  FCurrRec.Deleted := TRUE;
end;


Procedure TMemTable.DeleteRecord( pRecBuff : Pointer );
var
  T : TMemTableRecord;
begin
  T := FCurrRec;
  T.Free;
  State := TblOnCrack;
end;


Procedure TMemTable.AppendRecordWithBookMark( pRecBuff, BookMark, Data : Pointer );
begin
  TMemTableRecord.Create( Self, FRecords, dbiNOLOCK, pRecBuff, BookMark, FRecSize, BookMarkSize );
  LastRecordRaw;
  UpdateTableState;
end;


Procedure TMemTable.AppendRecord ( pRecBuff : Pointer );
begin
  AppendRecordWithBookMark( pRecBuff, NIL, NIL );
end;


Procedure TMemTable.UnDeleteRecord;
begin
  FCurrRec := FetchRecordFromCache;
  ValidatePointer( FCurrRec, DBIERR_NOCURRREC );
  FCurrRec.Deleted := FALSE;
end;


Procedure TMemTable.CommitUpdates;
var
  i : Integer;
begin
  For i := Pred( FRecords.Count ) DownTo 0 do
  begin
    FCurrRec := TMemTableRecord( FRecords.Items[ i ] );
    FCurrRec.Free;
  end;
  FRecords.Clear;
end;


Procedure TMemTable.PrepareUpdates;
var
  i : Integer;
begin
  ValidateHandle( FMaster );
  For i := Pred( FRecords.Count ) DownTo 0 do
  begin
    Try
      FCurrRec := TMemTableRecord( FRecords.Items[ i ] );
      if ( FCurrRec <> NIL ) then
      begin
        Case FCurrRec.UpdateStatus of
          usModified:
            begin
              FMaster.SetToBookMark( FCurrRec.FBookMark );
              FMaster.CacheLockRecord( dbiWRITELOCK );
              FMaster.ModifyRecord( FCurrRec.FRecBuff, TRUE );
            end;
          usInserted:
            FMaster.AppendRecord( FCurrRec.FRecBuff );
          usDeleted:
            begin
              FMaster.SetToBookMark( FCurrRec.FBookMark );
              FMaster.DeleteRecord( FCurrRec.FRecBuff );
            end;
        end;
        FCurrRec.FCommitted := TRUE;
      end;
    Except
      On E:ETitanEngineError do
        ;
    end;
  end;
end;


Procedure TMemTable.EmptyTable;
begin
  FRecords.FreeAll;
  FRecIndex := 0;
  State     := TblNoPos;
end;


Procedure TMemTable.MapGet( DType, DSize, DDec, LSize : SmallInt;
           Src, Dest : Pointer; Var Blank : Bool );
begin
  Move( Src^, Dest^, LSize );
  Blank  := FALSE;
end;


Procedure TMemTable.MapPut( DType, DSize, DDec, LSize : SmallInt;
            Src, Dest : Pointer );
begin
  Move( Src^, Dest^, LSize );
end;



(*== TBASECACHETABLE =======================================*)


Function TBaseCacheTable.GetTableName : PChar;
begin
  Result := FMainCursor.TableName;
end;


Procedure TBaseCacheTable.SetTableName( P : PChar );
begin
  FMainCursor.TableName := P;
end;


Function TBaseCacheTable.GetFileName : PChar;
begin
  Result := FMainCursor.FileName;
end;


Procedure TBaseCacheTable.SetFileName( P : PChar );
begin
  FMainCursor.FileName := P;
end;


Procedure TBaseCacheTable.GetFieldFromOffset( Offset, Size : Integer; pFDesc : pFLDDesc );
begin
  FMainCursor.GetFieldFromOffset( Offset, Size, pFDesc );
end;


Function TBaseCacheTable.GetSearchAction( bKeyIncl, bNext : Boolean ) : TCmpType;
begin
  Result := FMainCursor.GetSearchAction( bKeyIncl, bNext );
end;


Function TBaseCacheTable.GetBufferSize : Word;
begin
  Result := FMainCursor.GetBufferSize;
end;


Function TBaseCacheTable.GetBookMarkSize : Integer;
begin
  Result := FMainCursor.GetBookMarkSize;
end;


Constructor TBaseCacheTable.Create( Main : TBaseTable );
var
  Props : CURProps;
begin
  FMainCursor := Main;
  Try
    Main.GetCursorProps( Props );
  Except
    On E:ETitanEngineError Do
      begin
        Props.eOpenMode  := dbiREADWRITE;
        Props.eShareMode := dbiOPENSHARED;
      end;
  end;
  Inherited Create( Main.Parent, Main.Container, Main.TableName, NIL, 0, Props.eOpenMode, Props.eShareMode );
  FWorkBookMark  := AllocMem( MainCursor.BookMarkSize );
  FUpdateInfo := [ rtModified, rtInserted, rtUnmodified ];
end;


Destructor TBaseCacheTable.Destroy;
begin
  FreeMem( FWorkBookMark, MainCursor.BookMarkSize );
  Inherited Destroy;
end;


Procedure TBaseCacheTable.InitTableStruct;
Var
  FieldDescs  : PFLDDesc;
  CursorProps : CurProps;
begin
  FMainCursor.GetCursorProps( CursorProps );
  FieldDescs := AllocMem( CursorProps.iFields * SizeOf( FLDDesc ) );
  Try
    FMainCursor.GetFieldDescs( FieldDescs );
    FCache := TMemTable.Create( Self, NIL, FMainCursor.TableName,
                CursorProps.iFields, FMainCursor.BookMarkSize, FieldDescs, FMainCursor );
  Finally
    FreeMem( FieldDescs, CursorProps.iFields * SizeOf( FLDDesc ) );
  end;
end;


Procedure TBaseCacheTable.DoneTableStruct;
begin
  FCache.Free;
end;


Procedure TBaseCacheTable.FirstRecordRaw;
begin
  FMainCursor.FirstRecordRaw;
end;


Procedure TBaseCacheTable.LastRecordRaw;
begin
  FMainCursor.LastRecordRaw;
end;


Procedure TBaseCacheTable.NextRecordRaw;
begin
  FMainCursor.NextRecordRaw;
end;


Procedure TBaseCacheTable.PrevRecordRaw;
begin
  FMainCursor.PrevRecordRaw;
end;


Procedure TBaseCacheTable.TranslateGet(
           P             : TFieldCacheItem;                 { Field Description Info }
           pRecBuff      : Pointer;                         { Record buffer }
           pDest         : Pointer;                         { Destination field buffer }
           var bBlank    : Bool                             { Returned : is field blank }
         );
begin
  FMainCursor.TranslateGet( P, pRecBuff, pDest, bBlank );
end;


Procedure TBaseCacheTable.TranslatePut(
           P             : TFieldCacheItem;                 { Field Description Info }
           pRecBuff      : Pointer;                         { Record buffer }
           pSrc          : Pointer                          { Source field buffer }
         );
begin
  FMainCursor.TranslatePut( P, pRecBuff, pSrc );
end;


Procedure TBaseCacheTable.LoadDriverHeader;
begin
  FMainCursor.LoadDriverHeader;
end;


Procedure TBaseCacheTable.GetFieldCount( Var Fields, RecSize : Word );
begin
  FMainCursor.GetFieldCount( Fields, RecSize );
end;


Procedure TBaseCacheTable.OpenTable;
begin
  FMainCursor.OpenTable;
end;


Procedure TBaseCacheTable.CloseTable;
begin
  FMainCursor.CloseTable;
end;


Procedure TBaseCacheTable.Clone( bReadOnly : Bool; bUniDirectional : Bool;
           var hCurNew : hDBICur );
begin
  FMainCursor.Clone( bReadOnly, bUniDirectional, hCurNew );
end;


Procedure TBaseCacheTable.OpenIndex (                       { Open an index }
           pszIndexName  : PChar;                           { Index Name }
           iIndexId      : Word                             { Index number (if applicable) }
         );
begin
  FMainCursor.OpenIndex( pszIndexName, iIndexId );
end;


Procedure TBaseCacheTable.CloseIndex (                      { Close an index }
           pszIndexName  : PChar;                           { Index Name }
           iIndexId      : Word                             { Index number (if applicable) }
         );
begin
  FMainCursor.CloseIndex( pszIndexName, iIndexId );
end;


Procedure TBaseCacheTable.GetNativeDesc( iField : Integer; Src : Pointer; P : pFldDesc;
           Var LocType, LocSize : Word );
begin
  FMainCursor.GetNativeDesc( iField, Src, P, LocType, LocSize );
end;


Procedure TBaseCacheTable.GetFieldDescs( pFDesc : pFLDDesc );
begin
  FMainCursor.GetFieldDescs( pFDesc );
end;


Procedure TBaseCacheTable.SetToBegin;
begin
  FMainCursor.SetToBegin;
end;


Procedure TBaseCacheTable.SetToEnd;
begin
  FMainCursor.SetToEnd;
end;


Procedure TBaseCacheTable.GetBookMark( P : Pointer );
begin
  FMainCursor.GetBookMark( P );
end;


Procedure TBaseCacheTable.SetToBookmark( P : Pointer );
begin
  FMainCursor.SetToBookmark( P );
end;


Procedure TBaseCacheTable.GetRecordWithBookMark( P, pRecBuff : Pointer; eLock : dbiLockType );
begin
  FMainCursor.GetRecordWithBookMark( P, pRecBuff, eLock );
end;


Procedure TBaseCacheTable.CompareBookMarks( pBookMark1, pBookMark2 : Pointer;
           var CmpBkmkResult : CmpBkmkRslt );
begin
  FMainCursor.CompareBookMarks( pBookMark1, pBookMark2, CmpBkmkResult );
end;


Function TBaseCacheTable.ShowRecordInCache( pRecBuff : Pointer; pProps : pRECProps ) : Boolean;
var
  InCache : Boolean;
begin
  Result  := TRUE;
  InCache := TRUE;
  Try
    FMainCursor.GetBookMark( FWorkBookMark );
    FCache.SetToBookMark( FWorkBookMark );
  Except
    on E:ETitanEngineError do
      InCache := FALSE;
  end;
  If FCache.IncludeRecordinView( FUpdateInfo, InCache ) then
  begin
    If InCache then
    begin
      If not FGetOldRec and ( pRecBuff <> NIL ) and ( FCache.FCurrRec.Buffer <> NIL ) then
        Move( FCache.FCurrRec.Buffer^, pRecBuff^, FMainCursor.BufferSize );
      If ( pProps <> NIL ) then
        Move( FCache.FCurrRec.FRecProps, pProps^, Sizeof( RECProps ) );
    end
    else
      If ( pProps <> NIL ) then
        MoveZero( pProps^, Sizeof( RECProps ) );
  end
  else
    Result := FALSE
end;


Procedure TBaseCacheTable.LoadProperties( pRecProps : pRECProps );
begin
  FMainCursor.LoadProperties( pRecProps );
end;


Procedure TBaseCacheTable.FirstRecord;
begin
  FMainCursor.FirstRecord;
  if Not ShowRecordInCache( NIL, NIL ) then
    GetNextRecord( dbiNOLOCK, NIL, NIL );
end;


Procedure TBaseCacheTable.LastRecord;
begin
  FMainCursor.LastRecord;
  if Not ShowRecordInCache( NIL, NIL ) then
    GetPriorRecord( dbiNOLOCK, NIL, NIL );
end;


Procedure TBaseCacheTable.GetNextRecord (                   { Find/Get the next record }
           eLock         : DBILockType;                     { Optional lock request }
           pRecBuff      : Pointer;                         { Record buffer(client) }
           pRecProps     : pRECProps                        { Optional record properties }
         );
begin
  Repeat
    FMainCursor.GetNextRecord( eLock, pRecBuff, pRecProps );
    if ShowRecordInCache( pRecBuff, pRecProps ) then
      Exit;
  until FALSE;
end;


Procedure TBaseCacheTable.GetPriorRecord (                  { Find/Get the prior record }
           eLock         : DBILockType;                     { Optional lock request }
           pRecBuff      : Pointer;                         { Record buffer(client) }
           pRecProps     : pRECProps                        { Optional record properties }
         );
begin
  Repeat
    FMainCursor.GetPriorRecord( eLock, pRecBuff, pRecProps );
    if ShowRecordInCache( pRecBuff, pRecProps ) then
      Exit;
  until FALSE;
end;


Procedure TBaseCacheTable.GetRecord (                       { Gets the current record }
           eLock         : DBILockType;                     { Optional lock request }
           pRecBuff      : Pointer;                         { Record buffer(client) }
           pRecProps     : pRECProps                        { Optional record properties }
         );
begin
  FMainCursor.GetRecord( eLock, pRecBuff, pRecProps );
  if Not ShowRecordInCache( pRecBuff, pRecProps ) then
    ThrowException( DBIERR_NOCURRREC );
end;


Procedure TBaseCacheTable.GetRecordForKey ( bDirectKey : Bool; iFields, iLen : Word; pKey, pRecBuff : Pointer );
begin
  FMainCursor.GetRecordForKey( bDirectKey, iFields, iLen, pKey, pRecBuff );
end;


Procedure TBaseCacheTable.GetVchkDesc (                     { Get valcheck descriptor }
           iValSeqNo     : Word;                            { Valcheck sequence number }
           pvalDesc      : pVCHKDesc                        { Returned valcheck description }
         );
begin
  FMainCursor.GetVchkDesc( iValSeqNo, pvalDesc );
end;


Procedure TBaseCacheTable.GetRintDesc (                     { Get referential integrity descriptor }
           iRintSeqNo    : Word;                            { Rint sequence number }
           printDesc     : pRINTDesc                        { Returned rint description }
         );
begin
  FMainCursor.GetRintDesc( iRintSeqNo, printDesc );
end;


Procedure TBaseCacheTable.AcqTableLock (                    { Lock a table }
           eLockType     : DBILockType                      { Lock type }
         );
begin
  FMainCursor.AcqTableLock( eLockType );
end;


Procedure TBaseCacheTable.RelTableLock (                    { Unlocks Table level locks }
           bAll          : Bool;                            { True for all table level locks }
           eLockType     : DBILockType                      { Specific lock type }
         );
begin
  FMainCursor.RelTableLock( bAll, eLockType );
end;


Procedure TBaseCacheTable.RelRecordLock (                   { Releases record level locks }
           bAll          : Bool                             { True for all. Default Current. }
         );
begin
  FMainCursor.RelRecordLock( bAll );
end;


Procedure TBaseCacheTable.IsRecordLocked (                  { Check if current record is locked }
           var bLocked   : Bool                             { Rec lock status }
         );
begin
  FMainCursor.IsRecordLocked( bLocked );
end;


Procedure TBaseCacheTable.IsTableLocked (                   { Verify if Table is locked }
           epdxLock      : DBILockType;                     { Lock type to verify }
           var iLocks    : Word                             { Nbr of locks of the given type }
         );
begin
  FMainCursor.IsTableLocked( epdxLock, iLocks );
end;


Procedure TBaseCacheTable.IsTableShared (                   { Verify if this is a shared table }
           var bShared   : Bool                             { Shared status }
         );
begin
  FMainCursor.IsTableShared( bShared );
end;


Procedure TBaseCacheTable.InitRecord( pRecBuff : Pointer );
begin
  FMainCursor.InitRecord( pRecBuff );
end;


Procedure TBaseCacheTable.InsertRecord( eLock : DBILockType; pRecBuff : Pointer );
begin
  FCache.InsertRecord( eLock, pRecBuff );
end;


Procedure TBaseCacheTable.AppendRecord( pRecBuff : Pointer );
begin
  FCache.AppendRecord( pRecBuff );
end;


Procedure TBaseCacheTable.ModifyRecord( pRecBuff : Pointer; bFreeLock : Bool );
begin
  FMainCursor.GetBookMark( FWorkBookMark );
  FCache.ModifyRecordWithBookMark( pRecBuff, FWorkBookMark, NIL );
end;


Procedure TBaseCacheTable.DeleteRecord( pRecBuff : Pointer );
begin
  FMainCursor.GetBookMark( FWorkBookMark );
  FCache.DeleteRecordWithBookMark( pRecBuff, FWorkBookMark );
end;


Procedure TBaseCacheTable.UnDeleteRecord;
begin
  FMainCursor.UnDeleteRecord;
end;



Procedure TBaseCacheTable.ReadBlock ( Var iRecords : Longint; pBuf : Pointer );
begin
  FMainCursor.ReadBlock( iRecords, pBuf );
end;


Procedure TBaseCacheTable.WriteBlock ( Var iRecords : Longint; pBuf : Pointer );
begin
  FMainCursor.WriteBlock( iRecords, pBuf );
end;


Procedure TBaseCacheTable.GetSeqNo (                        { Get logical record number }
            var iSeqNo    : Longint                         { Pointer to sequence number }
          );
begin
  FMainCursor.GetSeqNo( iSeqNo );
end;


Procedure TBaseCacheTable.SetToSeqNo (                      { Position to a logical record number }
           iSeqNo        : Longint                          { Sequence number }
         );
begin
  FMainCursor.SetToSeqNo( iSeqNo );
end;


Procedure TBaseCacheTable.GetCursorProps( var curProps : CURProps );
begin
  FMainCursor.GetCursorProps( curProps );
end;


Procedure TBaseCacheTable.GetRecordCount( Var iRecCount : Longint );
begin
  FMainCursor.GetRecordCount( iRecCount );
end;


Procedure TBaseCacheTable.GetExactRecordCount( Var iRecCount : Longint );
begin
  FMainCursor.GetExactRecordCount( iRecCount );
end;


Procedure TBaseCacheTable.SetToRecordNo (                   { Position to Physical Rec# }
           iRecNo        : Longint                          { Physical record number }
         );
begin
  FMainCursor.SetToRecordNo( iRecNo );
end;


Procedure TBaseCacheTable.SaveChanges;                      { flush all buffered changes }
begin
  FMainCursor.SaveChanges;
end;


Procedure TBaseCacheTable.ForceReread;                      { reread buffered record }
begin
  FMainCursor.ForceReread;
end;


Procedure TBaseCacheTable.ForceRecordReread (               { Force Reread of current record from Server }
           pRecBuff      : Pointer                          { Returned : record buffer }
         );
begin
  FMainCursor.ForceRecordReread( pRecBuff );
end;


Procedure TBaseCacheTable.OpenLockList (                    { Get a list of locks }
           bAllUsers     : Bool;                            { True, for all Users locks }
           bAllLockTypes : Bool;                            { True, for all lock types }
           var hLocks    : hDBICur                          { Returned cursor on Lock list }
         );
begin
  FMainCursor.OpenLockList( bAllUsers, bAllLockTypes, hLocks );
end;


Procedure TBaseCacheTable.MakePermanent (                   { Make temporary table permanent }
           pszName       : PChar;                           { Rename temporary table }
           bOverWrite    : Bool                             { Overwrite existing file }
         );
begin
  FMainCursor.MakePermanent( pszName, bOverWrite );
end;


Procedure TBaseCacheTable.SetRange (                        { Set cursor to a range }
           bKeyItself    : Bool;                            { Whether Key or Record buffer }
           iFields1      : Word;                            { Key fields to be mathced in full }
           iLen1         : Word;                            { Key length to compare }
           pKey1         : Pointer;                         { Top/Left key in Range }
           bKey1Incl     : Bool;                            { If Inclusive of Key1 }
           iFields2      : Word;                            { Key fields to be mathced in full }
           iLen2         : Word;                            { Key length to compare }
           pKey2         : Pointer;                         { Bottom/Right key in Range }
           bKey2Incl     : Bool                             { If Inclusive of Key2 }
         );
begin
  FMainCursor.SetRange( bKeyItself, iFields1, iLen1, pKey1, bKey1Incl,
    iFields2, iLen2, pKey2, bKey2Incl );
end;



Procedure TBaseCacheTable.ResetRange;
begin
  FMainCursor.ResetRange;
end;



Procedure TBaseCacheTable.CompareKeys (                     { Compare two keys }
           pKey1         : Pointer;                         { Key buffer 1 to compare }
           pKey2         : Pointer;                         { Key buffer 2 (Or NULL) }
           iFields       : Word;                            { Fields to compare in full }
           iLen          : Word;                            { Partial key to compare }
           var iResult   : SmallInt                         { Compare result }
         );
begin
  FMainCursor.CompareKeys( pKey1, pKey2, iFields, iLen, iResult );
end;


Procedure TBaseCacheTable.SwitchToIndex(
           pszIndexName  : PChar;
           pszTagName    : PChar;
           iIndexId      : Word;
           bCurrRec      : Bool
         );
begin
  { Bookmarks are used to keep track of records, so there is no way }
  { to change indexes once using delayed updates.                   }
  ThrowException( DBIERR_NOSUCHINDEX );
end;


Procedure TBaseCacheTable.SetToKey (                        { Set key condition }
           eSearchCond   : DBISearchCond;                   { Search condition (default is =) }
           bDirectKey    : Bool;                            { Key is supplied directly }
           iFields       : Word;                            { No of full fields to match }
           iLen          : Word;                            { Partial key len of last field }
           pBuff         : Pointer                          { Either Record buffer or Key itself }
         );
begin
  FMainCursor.SetToKey( eSearchCond, bDirectKey, iFields, iLen, pBuff );
end;


Procedure TBaseCacheTable.SetToKeySpecial(                  { Set key condition }
           Action        : TCmpType;                        { Search condition (default is =) }
           bDirectKey    : Bool;                            { Key is supplied directly }
           iFields       : Word;                            { No of full fields to match }
           iLen          : Word;                            { Partial key len of last field }
           pBuff         : Pointer;                         { Either Record buffer or Key itself }
           pRetBuff      : Pointer                          { Return Buffer }
         );
begin
  FMainCursor.SetToKeySpecial( Action, bDirectKey, iFields, iLen, pBuff, pRetBuff );
end;


Procedure TBaseCacheTable.ExtractKey (                      { Get the key value of current record }
           pRecBuf       : Pointer;                         { Record buffer (optional) }
           pKeyBuf       : Pointer                          { Returned. Key bytes. }
         );
begin
  FMainCursor.ExtractKey( pRecBuf, pKeyBuf );
end;


Procedure TBaseCacheTable.ExtractKeyPrecise(                { Get the key value of current record }
           pRecBuf       : Pointer;                         { Record buffer (optional) }
           pKeyBuf       : Pointer;                         { Returned. Key bytes. }
           iFields       : word;                            { # of Fields or 0 }
           iLen          : word;                            { len of last field }
           var iKeyLen   : word
         );
begin
  FMainCursor.ExtractKeyPrecise( pRecBuf, pKeyBuf, iFields, iLen, iKeyLen );
end;


Procedure TBaseCacheTable.GetIndexDesc (                    { Get index properties }
           iIndexSeqNo   : Word;                            { Index number }
           var idxDesc   : IDXDesc                          { Returned index description }
         );
begin
  FMainCursor.GetIndexDesc( iIndexSeqNo, idxDesc );
end;


Procedure TBaseCacheTable.GetIndexDescs (                   { Get index properties }
           idxDesc   : PIDXDesc                             { Returned index description }
         );
begin
  FMainCursor.GetIndexDescs( idxDesc );
end;


Procedure TBaseCacheTable.GetIndexForField(                 { Get index properties }
           iFld          : Word;                            { Field Number (1..N) }
           bProdTagOnly  : Bool;                            { If TRUE, only xBASE prod tags will be returned }
           var   idxDesc : IDXDesc                          { Returned index description }
         );
begin
  FMainCursor.GetIndexForField( iFld, bProdTagOnly, idxDesc );
end;


Procedure TBaseCacheTable.GetIndexSeqNo (                   { Get index sequence number }
           pszIndexName  : PChar;                           { Index name }
           pszTagName    : PChar;                           { Tag name (if applicable) }
           iIndexId      : Word;                            { Index number }
           var iIndexSeqNo  : Word                          { Index number }
         );
begin
  FMainCursor.GetIndexSeqNo( pszIndexName, pszTagName, iIndexId, iIndexSeqNo );
end;


Procedure TBaseCacheTable.EmptyTable;                       { Deletes all records }
begin
  FMainCursor.EmptyTable;
end;


Procedure TBaseCacheTable.AddIndex (                        { Add a new index }
           var IdxDesc   : IDXDesc;                         { Description of the index }
           pszKeyviolName : PChar                           { Keyviol table name (optional) }
         );
begin
  FMainCursor.AddIndex( IdxDesc, pszKeyViolName );
end;


Procedure TBaseCacheTable.DeleteIndex (                     { Delete index }
           pszIndexName  : PChar;                           { Index name }
           pszIndexTagName : PChar;                         { Index tagname (xbase MDX) }
           iIndexId      : Word                             { Index number }
         );
begin
  FMainCursor.DeleteIndex( pszIndexName, pszIndexTagName, iIndexId );
end;


Procedure TBaseCacheTable.BeginDelayedUpdates (             { put cursor in delayed update mode }
           var hCursor   : hDBICur                          { In/Out : returns new Cursor }
         );
begin
  { We don't want to allow recursive delayed updates! }
  Not_Supported( fnBEGINDELAYEDUPDATES );
end;


Procedure TBaseCacheTable.EndDelayedUpdates (               { Convert cursor back to normal cursor }
           var hCursor   : hDBICur                          { In/Out : returns original Cursor }
         );
var
  P : TBaseCacheTable;
begin
  P       := TBaseCacheTable( hCursor );
  hCursor := hDBICur( P.MainCursor );
  P.Free;
end;


Procedure TBaseCacheTable.ApplyDelayedUpdates (             { Perform the specified operation. }
           eUpdCmd       : DBIDelayedUpdCmd                 { Op Type: Commit or Rollback. }
         );
begin
  Case eUpdCmd of
    dbiDelayedUpdCommit:                { Commit the updates }
      FCache.CommitUpdates;
    dbiDelayedUpdCancel:                { Rollback the updates }
      FCache.EmptyTable;
    dbiDelayedUpdCancelCurrent:         { Cancel the Current Rec Change }
      begin
        Try
          FMainCursor.GetBookMark( FWorkBookMark );
          FCache.SetToBookMark( FWorkBookMark );
          FCache.DeleteRecord( NIL );
        Except
          On E:ETitanEngineError do
            ;
        end;
      end;
    dbiDelayedUpdPrepare:               { Phase1 of 2 phase commit }
      FCache.PrepareUpdates;
  end;
end;


Procedure TBaseCacheTable.GetDelayedUpdates (
           var hCache    : hDBICur                          { In/Out: returns cursor on cache }
         );
begin
  hCache := hDBICur( FCache );
  ValidateParameter( hCache );
end;


Procedure TBaseCacheTable.LockRecord( eLock : DBILockType );
begin
  FMainCursor.LockRecord( eLock );
end;



Procedure TBaseCacheTable.GetLdObj (                        { Get language driver }
           var   pLdObj  : Pointer                          { Returned language driver object }
         );
begin
  FMainCursor.GetLdObj( pLdObj );
end;


Procedure TBaseCacheTable.OpenBlob (                        { Open a blob for access }
           pRecBuf       : Pointer;                         { Record Buffer }
           iField        : Word;                            { Field number (1..n) }
           eOpenMode     : DBIOpenMode                      { Open for Read or RW }
         );
begin
  FMainCursor.OpenBlob( pRecBuf, iField, eOpenMode );
end;


Procedure TBaseCacheTable.GetBlobSize (                     { Get Blob Size }
           pRecBuf       : Pointer;                         { Record Buffer }
           iField        : Word;                            { Field number (1..n) }
           var iSize     : Longint                          { returned size }
         );
begin
  FMainCursor.GetBlobSize( pRecBuf, iField, iSize );
end;


Procedure TBaseCacheTable.GetBlob (                         { Read bytes from blob }
           pRecBuf       : Pointer;                         { Record Buffer }
           iField        : Word;                            { Field number of blob (1..n) }
           iOffSet       : Longint;                         { Starting position   }
           iLen          : Longint;                         { No of bytes to be read   }
           pDest         : Pointer;                         { Destination }
           var iRead     : Longint                          { Actual no of bytes read }
         );
begin
  FMainCursor.GetBlob( pRecBuf, iField, iOffset, iLen, pDest, iRead );
end;


Procedure TBaseCacheTable.PutBlob (                         { Write bytes to blob }
           pRecBuf       : Pointer;                         { Record Buffer }
           iField        : Word;                            { Field number of blob (1..n) }
           iOffSet       : Longint;                         { Starting position   }
           iLen          : Longint;                         { No of bytes to put   }
           pSrc          : Pointer                          { pntr to Source }
         );
begin
  FMainCursor.PutBlob( pRecBuf, iField, iOffset, iLen, pSrc );
end;


Procedure TBaseCacheTable.TruncateBlob (                    { Reduces the blob size }
           pRecBuf       : Pointer;                         { Record Buffer }
           iField        : Word;                            { Field number of blob (1..n) }
           iLen          : Longint                          { New blob length }
         );
begin
  FMainCursor.TruncateBlob( pRecBuf, iField, iLen );
end;


Procedure TBaseCacheTable.FreeBlob (                        { Free the blob }
           pRecBuf       : Pointer;                         { Record Buffer }
           iField        : Word                             { Field number of blob (1..n) }
         );
begin
  FMainCursor.FreeBlob( pRecBuf, iField );
end;


Procedure TBaseCacheTable.GetBlobHeading (                  { Get Blob Heading }
           iField        : Word;                            { Field number of blob (1..n) }
           pRecBuf       : Pointer;                         { Record buffer of owner record }
           pDest         : Pointer                          { Destination buffer }
         );
begin
  FMainCursor.GetBlobHeading( iField, pRecBuf, pDest );
end;


Procedure TBaseCacheTable.SetFieldMap (                     { Set a fieldmap }
           iFields       : Word;                            { Number of fields }
           pFldDesc      : pFLDDesc                         { Array of field descriptions }
         );
begin
  FMainCursor.SetFieldMap( iFields, pFldDesc );
end;


Procedure TBaseCacheTable.GetField(                         { Get Field value }
           iField        : Word;                            { Field # (1..n) }
           pRecBuff      : Pointer;                         { Record buffer }
           pDest         : Pointer;                         { Destination field buffer }
           var bBlank    : Bool                             { Returned : is field blank }
         );
begin
  FMainCursor.GetField( iField, pRecBuff, pDest, bBlank );
end;


Procedure TBaseCacheTable.PutField (                        { Put a value in the record buffer }
           iField        : Word;                            { Field # (1..n) }
           pRecBuff      : Pointer;                         { Record buffer }
           pSrc          : Pointer                          { Source field buffer }
         );
begin
  FMainCursor.PutField( iField, pRecBuff, pSrc );
end;


Procedure TBaseCacheTable.VerifyField (                     { Verifies the field value }
           iField        : Word;                            { Field # (1..n) }
           pSrc          : Pointer;                         { Field Value }
           var bBlank    : Bool                             { Field is Blank (Returned) }
         );
begin
  FMainCursor.VerifyField( iField, pSrc, bBlank );
end;


Procedure TBaseCacheTable.AddFilter (                       { Add a filter to the cursor }
           iClientData   : Longint;                         { Client supplied data      (opt) }
           iPriority     : Word;                            { 1..N with 1 being highest (opt) }
           bCanAbort     : Bool;                            { TRUE if pfFiltercan return ABORT (opt) }
           pcanExpr      : pCANExpr;                        { Expression tree        (opt) }
           pfFilter      : pfGENFilter;                     { ptr to filter function (opt) }
           var hFilter   : hDBIFilter                       { Returns filter handle }
         );
begin
  FMainCursor.AddFilter( iClientData, iPriority, bCanAbort, pcanExpr, pfFilter, hFilter );
end;


Procedure TBaseCacheTable.DropFilter (                      { Drop a filter }
           hFilter       : hDBIFilter                       { Filter handle }
         );
begin
  FMainCursor.DropFilter( hFilter );
end;


Procedure TBaseCacheTable.ActivateFilter (                  { Activate a Filter }
           hFilter       : hDBIFilter                       { Filter handle }
         );
begin
  FMainCursor.ActivateFilter( hFilter );
end;


Procedure TBaseCacheTable.DeactivateFilter (                { Deactivate Filter }
           hFilter       : hDBIFilter                       { Filter handle }
         );
begin
  FMainCursor.DeactivateFilter( hFilter );
end;


Procedure TBaseCacheTable.GetFilterInfo (                   { Get filter information }
           hFilter       : hDBIFilter;                      { Filter handle          /NULL }
           iFilterId     : Word;                            { Filter id              /0 }
           iFilterSeqNo  : Word;                            { Filter sequence number /0 }
           var Filterinfo : FilterInfo                      { Returns filter info }
         );
begin
  FMainCursor.GetFilterInfo( hFilter, iFilterId, iFilterSeqNo, FilterInfo );
end;


Procedure TBaseCacheTable.GetProp (                         { Get property }
           iProp         : Longint;                         { Property to retrieve }
           PropValue     : Pointer;                         { == NULL, validate iProp for getting }
           iMaxLen       : Word;                            { Length of buffer pPropValue }
           var   iLen    : Word                             { Returns required length }
         );
begin
  Case TPropertyRec( iProp ).Prop of
(*
  curDELAYUPDRECSTATE     = $05050001;  { ro DELYUPDCbDesc }
  curDELAYUPDABORTRESTORE = $05050002;  { rw BOOL, restore state }
  curDELAYUPDUSECALLBACK  = $05050006;  { rw BOOL, callback usr. }
*)
    Word( curDELAYUPDDISPLAYOPT ):
      begin
        iLen := Sizeof( FUpdateInfo );
        Move( FUpdateInfo, PropValue^, iLen );
      end;
    Word( curDELAYUPDNUMUPDATES ):
      begin
        iLen := Sizeof( Integer );
        Integer( PropValue^ ) := FCache.FRecords.Count;
      end;
    Word( curDELAYUPDGETOLDRECORD ):
      begin
        iLen := Sizeof( Boolean );
        Boolean( PropValue^ ) := FGetOldRec;
      end;
  else
    FMainCursor.GetProp( iProp, PropValue, iMaxLen, iLen );
  end;
end;


Procedure TBaseCacheTable.SetProp (                         { Get property }
           iProp         : Longint;                         { Property to retrieve }
           PropValue     : Longint                          { == NULL, validate iProp for getting }
         );
begin
  Case TPropertyRec( iProp ).Prop of
(*
  curDELAYUPDABORTRESTORE = $05050002;  { rw BOOL, restore state }
  curDELAYUPDGETOLDRECORD = $05050004;  { rw BOOL, get un-modified }
  curDELAYUPDUSECALLBACK  = $05050006;  { rw BOOL, callback usr. }
*)
    Word( curDELAYUPDDISPLAYOPT ):
      FUpdateInfo := TUpdateRecordTypes( Byte( PropValue ) );
    Word( curDELAYUPDGETOLDRECORD ):
      FGetOldRec := ( PropValue > 0 );
  else
    FMainCursor.SetProp( iProp, PropValue );
  end;
end;


Procedure TBaseCacheTable.ValidateProp (                    { Validate a property }
           iProp         : Longint;                         { property to validate }
           bSetting      : Bool                             { TRUE:setting, FALSE:getting }
         );
begin
  FMainCursor.ValidateProp( iProp, bSetting );
end;


end.
