Browse Source

* New algorith to store update-buffers to file
* RowStateToByte and ByteToRowState
* Start at the begin of a stream, after the automatic recognition of the stream has been used
* Implemented TBufDataset.CompareBookmarks
* Some update-buffer fixes
* Fixed some warnings

git-svn-id: trunk@12155 -

joost 16 years ago
parent
commit
d1beccce83
1 changed files with 179 additions and 159 deletions
  1. 179 159
      packages/fcl-db/src/base/bufdataset.pas

+ 179 - 159
packages/fcl-db/src/base/bufdataset.pas

@@ -76,6 +76,10 @@ type
      - If UpdateKind is ukDelete it contains a bookmark to the record just after the deleted record
 }
     BookmarkData       : TBufBookmark;
+{  DelBookMarkData:
+     - If UpdateKind is ukDelete it contains a bookmark to the deleted record, before it got deleted
+}
+    DelBookmarkData    : TBufBookmark;
 {  OldValuesBuffer:
      - If UpdateKind is ukModify it contains a record-buffer which contains the old data
      - If UpdateKind is ukDelete it contains a record-buffer with the data of the deleted record
@@ -105,7 +109,6 @@ type
   TBufIndex = class(TObject)
   private
     FDataset : TBufDataset;
-
   protected
     function GetBookmarkSize: integer; virtual; abstract;
     function GetCurrentBuffer: Pointer; virtual; abstract;
@@ -306,22 +309,25 @@ type
   TDatapacketReaderClass = class of TDatapacketReader;
   TDataPacketReader = class(TObject)
     FStream : TStream;
+  protected
+    class function RowStateToByte(const ARowState : TRowState) : byte;
+    class function ByteToRowState(const AByte : Byte) : TRowState;
   public
     constructor create(AStream : TStream); virtual;
 
     procedure LoadFieldDefs(AFieldDefs : TFieldDefs); virtual; abstract;
     procedure StoreFieldDefs(AFieldDefs : TFieldDefs); virtual; abstract;
-    procedure GetRecordUpdState(var AIsUpdate,AAddRecordBuffer,AIsFirstEntry : boolean); virtual; abstract;
-    procedure EndStoreRecord(const AChangeLog : TChangeLogEntryArr); virtual; abstract;
+    function GetRecordRowState(out AUpdOrder : Integer) : TRowState; virtual; abstract;
+    procedure EndStoreRecord; virtual; abstract;
     function GetCurrentRecord : boolean; virtual; abstract;
     procedure GotoNextRecord; virtual; abstract;
     function GetCurrentElement : pointer; virtual; abstract;
     procedure GotoElement(const AnElement : pointer); virtual; abstract;
     procedure RestoreRecord(ADataset : TBufDataset); virtual; abstract;
-    procedure StoreRecord(ADataset : TBufDataset; RowState : TRowState); virtual; abstract;
-    procedure InitLoadRecords(var AChangeLog : TChangeLogEntryArr); virtual; abstract;
-    property Stream: TStream read FStream;
+    procedure StoreRecord(ADataset : TBufDataset; ARowState : TRowState; AUpdOrder : integer = 0); virtual; abstract;
+    procedure InitLoadRecords; virtual; abstract;
     class function RecognizeStream(AStream : TStream) : boolean; virtual; abstract;
+    property Stream: TStream read FStream;
   end;
 
   { TFpcBinaryDatapacketReader }
@@ -330,16 +336,15 @@ type
   public
     procedure LoadFieldDefs(AFieldDefs : TFieldDefs); override;
     procedure StoreFieldDefs(AFieldDefs : TFieldDefs); override;
-    procedure GetRecordUpdState(var AIsUpdate, AAddRecordBuffer,
-                     AIsFirstEntry: boolean); override;
-    procedure EndStoreRecord(const AChangeLog : TChangeLogEntryArr); override;
+    function GetRecordRowState(out AUpdOrder : Integer) : TRowState; override;
+    procedure EndStoreRecord; override;
     function GetCurrentRecord : boolean; override;
     procedure GotoNextRecord; override;
     procedure GotoElement(const AnElement : pointer); override;
-    procedure InitLoadRecords(var AChangeLog : TChangeLogEntryArr); override;
+    procedure InitLoadRecords; override;
     function GetCurrentElement: pointer; override;
     procedure RestoreRecord(ADataset : TBufDataset); override;
-    procedure StoreRecord(ADataset : TBufDataset; RowState : TRowState); override;
+    procedure StoreRecord(ADataset : TBufDataset; ARowState : TRowState; AUpdOrder : integer = 0); override;
     class function RecognizeStream(AStream : TStream) : boolean; override;
   end;
 
@@ -385,7 +390,7 @@ type
     function GetIndexName: String;
     function LoadBuffer(Buffer : PChar): TGetResult;
     function GetFieldSize(FieldDef : TFieldDef) : longint;
-    function GetRecordUpdateBuffer(const ABookmark : TBufBookmark) : boolean;
+    function GetRecordUpdateBuffer(const ABookmark : TBufBookmark; IncludeDeleted : boolean = false; AFindNext : boolean = false) : boolean;
     function GetActiveRecordUpdateBuffer : boolean;
     procedure ProcessFieldCompareStruct(AField: TField; var ACompareRec : TDBCompareRec);
     procedure SetIndexFieldNames(const AValue: String);
@@ -395,7 +400,7 @@ type
     function  IntAllocRecordBuffer: PChar;
     procedure DoFilterRecord(var Acceptable: Boolean);
     procedure ParseFilter(const AFilter: string);
-    procedure IntLoadFielddefsFromFile(const FileName: string);
+    procedure IntLoadFielddefsFromFile;
     procedure IntLoadRecordsFromFile;
   protected
     procedure UpdateIndexDefs; override;
@@ -466,6 +471,7 @@ type
     procedure LoadFromFile(AFileName: string = ''; Format: TDataPacketFormat = dfAny);
     procedure SaveToFile(AFileName: string = ''; Format: TDataPacketFormat = dfBinary);
     procedure CreateDataset;
+    function CompareBookmarks(Bookmark1, Bookmark2: TBookmark): Longint; override;
 
     property ChangeCount : Integer read GetChangeCount;
     property MaxIndexesCount : Integer read FMaxIndexesCount write SetMaxIndexesCount;
@@ -913,7 +919,7 @@ begin
     FFileStream := TFileStream.Create(FileName,fmOpenRead);
     FDatasetReader := TFpcBinaryDatapacketReader.Create(FFileStream);
     end;
-  if assigned(FDatasetReader) then IntLoadFielddefsFromFile(FFileName);
+  if assigned(FDatasetReader) then IntLoadFielddefsFromFile;
   CalcRecordSize;
 
   FBRecordcount := 0;
@@ -1516,21 +1522,30 @@ begin
 {$ENDIF}
 end;
 
-function TBufDataset.GetRecordUpdateBuffer(const ABookmark: TBufBookmark): boolean;
+function TBufDataset.GetRecordUpdateBuffer(const ABookmark : TBufBookmark; IncludeDeleted : boolean = false; AFindNext : boolean = false): boolean;
 
-var x : integer;
+var x        : integer;
+    StartBuf : integer;
 
 begin
+  if AFindNext then
+    begin
+    inc(FCurrentUpdateBuffer);
+    StartBuf:=FCurrentUpdateBuffer;
+    end
+  else
+    StartBuf := 0;
   if (FCurrentUpdateBuffer >= length(FUpdateBuffer)) or not FCurrentIndex.CompareBookmarks(@FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData,@ABookmark) then
-   for x := 0 to high(FUpdateBuffer) do
+   for x := StartBuf to high(FUpdateBuffer) do
     if FCurrentIndex.CompareBookmarks(@FUpdateBuffer[x].BookmarkData,@ABookmark) and
-       (FUpdateBuffer[x].UpdateKind<>ukDelete) then // The Bookmarkdata of a deleted record does not contain the deleted record, but the record thereafter
+       ((FUpdateBuffer[x].UpdateKind<>ukDelete) or IncludeDeleted) then // The Bookmarkdata of a deleted record does not contain the deleted record, but the record thereafter
       begin
       FCurrentUpdateBuffer := x;
       break;
       end;
   Result := (FCurrentUpdateBuffer < length(FUpdateBuffer))  and
-            (FCurrentIndex.CompareBookmarks(@FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData,@ABookmark));
+            (FCurrentIndex.CompareBookmarks(@FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData,@ABookmark)) and
+            ((FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind<>ukDelete) or IncludeDeleted) ;
 end;
 
 function TBufDataset.LoadBuffer(Buffer : PChar): TGetResult;
@@ -1711,7 +1726,8 @@ begin
 // may arise. The 'delete' is placed in the update-buffer before the actual delete
 // took place. This can lead into troubles, because other updates can depend on
 // the record still being available.
-  if not GetActiveRecordUpdateBuffer or (FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind = ukModify) then
+  if not GetActiveRecordUpdateBuffer or
+    (FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind = ukModify) then
     begin
     FCurrentUpdateBuffer := length(FUpdateBuffer);
     SetLength(FUpdateBuffer,FCurrentUpdateBuffer+1);
@@ -1719,15 +1735,15 @@ begin
     FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer := IntAllocRecordBuffer;
     move(RemRec^, FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer^,FRecordSize);
     FreeRecordBuffer(RemRecBuf);
-    FCurrentIndex.StoreCurrentRecIntoBookmark(@FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData);
     end
   else //with FIndexes[0] do
     begin
     FreeRecordBuffer(RemRecBuf);
-    FCurrentIndex.StoreCurrentRecIntoBookmark(@FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData);
     if FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind <> ukModify then
       FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer := nil;  //this 'disables' the updatebuffer
     end;
+  FCurrentIndex.StoreCurrentRecIntoBookmark(@FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData);
+  FUpdateBuffer[FCurrentUpdateBuffer].DelBookmarkData := RemRecBookmrk;
 
   dec(FBRecordCount);
   FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind := ukDelete;
@@ -2321,27 +2337,22 @@ begin
 end;
 
 procedure TBufDataset.GetDatasetPacket(AWriter: TDataPacketReader);
-var i              : integer;
-    ScrollResult   : TGetResult;
+var ScrollResult   : TGetResult;
     StoreDSState   : TDataSetState;
     ABookMark      : PBufBookmark;
     ATBookmark     : TBufBookmark;
-    ChangeLog      : array of TChangeLogEntry;
-
-var RowState : TRowState;
-    RecUpdBuf: integer;
-    EntryNr  : integer;
-    ChangeLogStr : String;
+    RowState       : TRowState;
+    EntryNr        : integer;
+    StoreUpdBuf    : integer;
+    RunNr          : integer;
 
 begin
   FDatasetReader := AWriter;
   try
-
-  //  CheckActive;
+    //CheckActive;
     ABookMark:=@ATBookmark;
     FDatasetReader.StoreFieldDefs(FieldDefs);
 
-    SetLength(ChangeLog,length(FUpdateBuffer));
     EntryNr:=1;
 
     StoreDSState:=State;
@@ -2350,71 +2361,43 @@ begin
     while ScrollResult=grOK do
       begin
       FCurrentIndex.StoreCurrentRecIntoBookmark(ABookmark);
-      if GetRecordUpdateBuffer(ABookmark^) and (FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind <> ukDelete) then
+      if GetRecordUpdateBuffer(ABookmark^,True) then
         begin
-        if FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind = ukInsert then
-          begin
-          RowState:=[rsvInserted];
-          FFilterBuffer:=FCurrentIndex.CurrentBuffer;
-          with ChangeLog[FCurrentUpdateBuffer] do
-            begin
-            OrigEntry:=0;
-            NewEntry:=EntryNr;
-            UpdateKind:=ukInsert;
-            end;
-          end
-        else // This is always ukModified
-          begin
-          RowState:=[rsvOriginal];
-          FFilterBuffer:=FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer;
-          ChangeLog[FCurrentUpdateBuffer].OrigEntry:=EntryNr;
-          end;
+        case FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind of
+          ukModify : begin
+                     FFilterBuffer:=FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer;
+                     FDatasetReader.StoreRecord(Self,[rsvOriginal],FCurrentUpdateBuffer);
+                     RowState:=[rsvUpdated];
+                     end;
+          ukDelete : begin
+                     repeat
+                     StoreUpdBuf := FCurrentUpdateBuffer;
+                     RunNr := 0;
+
+                     repeat
+                     inc(RunNr);
+                     Assert(FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind=ukDelete);
+                     FFilterBuffer:=FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer;
+                     FDatasetReader.StoreRecord(Self,[rsvDeleted],FCurrentUpdateBuffer);
+                     RowState:=[];
+                     until not GetRecordUpdateBuffer(FUpdateBuffer[FCurrentUpdateBuffer].DelBookmarkData,True,RunNr>1);
+
+                     FCurrentUpdateBuffer:=StoreUpdBuf;
+                     until not GetRecordUpdateBuffer(ABookmark^,True,True)
+                     end;
+        end; { case }
         end
       else
-        begin
-        FFilterBuffer:=FCurrentIndex.CurrentBuffer;
         RowState:=[];
-        end;
+      FFilterBuffer:=FCurrentIndex.CurrentBuffer;
+      FDatasetReader.StoreRecord(Self,RowState,FCurrentUpdateBuffer);
 
-      FDatasetReader.StoreRecord(Self,RowState);
       inc(EntryNr);
       ScrollResult:=FCurrentIndex.ScrollForward;
       end;
-
-    for RecUpdBuf:=0 to length(FUpdateBuffer)-1 do with FUpdateBuffer[RecUpdBuf] do
-      begin
-      if UpdateKind = ukDelete then
-        begin
-        RowState:=[rsvDeleted];
-        FFilterBuffer:=FUpdateBuffer[RecUpdBuf].OldValuesBuffer;
-        FDatasetReader.StoreRecord(Self, RowState);
-        with ChangeLog[RecUpdBuf] do
-          begin
-          NewEntry:=EntryNr;
-          UpdateKind:=ukDelete;
-          end;
-        inc(EntryNr);
-        end
-      else if UpdateKind = ukModify then
-        begin
-        RowState:=[rsvUpdated];
-        FCurrentIndex.GotoBookmark(@BookmarkData);
-        FFilterBuffer:=FCurrentIndex.CurrentBuffer;
-        FDatasetReader.StoreRecord(Self, RowState);
-        with ChangeLog[RecUpdBuf] do
-          begin
-          NewEntry:=EntryNr;
-          UpdateKind:=ukModify;
-          end;
-        inc(EntryNr);
-        end;
-      end;
-
     RestoreState(StoreDSState);
 
-    FDatasetReader.EndStoreRecord(ChangeLog);
-    SetLength(ChangeLog,0);
-
+    FDatasetReader.EndStoreRecord;
   finally
     FDatasetReader := nil;
   end;
@@ -2427,7 +2410,10 @@ begin
   if GetRegisterDatapacketReader(AStream,format,APacketReaderReg) then
     APacketReader := APacketReaderReg.ReaderClass.create(AStream)
   else if TFpcBinaryDatapacketReader.RecognizeStream(AStream) then
+    begin
+    AStream.Seek(0,soFromBeginning);
     APacketReader := TFpcBinaryDatapacketReader.create(AStream)
+    end
   else
     DatabaseError(SStreamNotRecognised);
   try
@@ -2472,7 +2458,16 @@ begin
   CreateFields;
 end;
 
-procedure TBufDataset.IntLoadFielddefsFromFile(const FileName: string);
+function TBufDataset.CompareBookmarks(Bookmark1, Bookmark2: TBookmark
+  ): Longint;
+begin
+  if FCurrentIndex.CompareBookmarks(Bookmark1,Bookmark2) then
+    Result := 0
+  else
+    Result := -1;
+end;
+
+procedure TBufDataset.IntLoadFielddefsFromFile;
 
 begin
   FDatasetReader.LoadFielddefs(FieldDefs);
@@ -2481,44 +2476,71 @@ end;
 
 procedure TBufDataset.IntLoadRecordsFromFile;
 
-
-var StoreState     : TDataSetState;
-    ChangeLog      : TChangeLogEntryArr;
-    ChangeLogStr   : string;
-    ChangeLogInfo  : TChangeLogInfoArr;
-    EntryNr        : integer;
-    i              : integer;
-    IsUpdate,
-    AddRecordBuffer,
-    IsFirstEntry    : boolean;
+var StoreState      : TDataSetState;
+    EntryNr         : integer;
+    AddRecordBuffer : boolean;
+    ARowState       : TRowState;
+    AUpdOrder       : integer;
 
 begin
-  FDatasetReader.InitLoadRecords(ChangeLog);
+  FDatasetReader.InitLoadRecords;
   EntryNr:=1;
   StoreState:=SetTempState(dsFilter);
-  SetLength(ChangeLogInfo,length(ChangeLog));
 
   while FDatasetReader.GetCurrentRecord do
     begin
-    FDatasetReader.GetRecordUpdState(IsUpdate,AddRecordBuffer,IsFirstEntry);
-
-    if IsUpdate then
+    ARowState := FDatasetReader.GetRecordRowState(AUpdOrder);
+    if rsvOriginal in ARowState then
       begin
-      if IsFirstEntry then
-        begin
-        for i := 0 to length(ChangeLog) -1 do
-          if ChangeLog[i].OrigEntry=EntryNr then break;
-        ChangeLogInfo[i].FirstChangeNode:=FDatasetReader.GetCurrentElement;
-        end
+      if length(FUpdateBuffer) < (AUpdOrder+1) then
+        SetLength(FUpdateBuffer,AUpdOrder+1);
+
+      FCurrentUpdateBuffer:=AUpdOrder;
+
+      FFilterBuffer:=IntAllocRecordBuffer;
+      fillchar(FFilterBuffer^,FNullmaskSize,0);
+      FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer := FFilterBuffer;
+      FDatasetReader.RestoreRecord(self);
+
+      FDatasetReader.GotoNextRecord;
+      if not FDatasetReader.GetCurrentRecord then
+        DatabaseError(SStreamNotRecognised);
+      ARowState := FDatasetReader.GetRecordRowState(AUpdOrder);
+      if rsvUpdated in ARowState then
+        FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind:= ukModify
       else
-        begin
-        for i := 0 to length(ChangeLog) -1 do
-          if ChangeLog[i].NewEntry=EntryNr then break;
-        ChangeLogInfo[i].SecondChangeNode:=FDatasetReader.GetCurrentElement;
-        end;
+        DatabaseError(SStreamNotRecognised);
 
-      FIndexes[0].StoreSpareRecIntoBookmark(@ChangeLogInfo[i].Bookmark);
-      end;
+      FFilterBuffer:=FIndexes[0].SpareBuffer;
+      FIndexes[0].StoreSpareRecIntoBookmark(@FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData);
+      fillchar(FFilterBuffer^,FNullmaskSize,0);
+
+      FDatasetReader.RestoreRecord(self);
+      FIndexes[0].AddRecord(IntAllocRecordBuffer);
+      inc(FBRecordCount);
+
+      AddRecordBuffer:=False;
+
+      end
+    else if rsvDeleted in ARowState then
+      begin
+      if length(FUpdateBuffer) < (AUpdOrder+1) then
+        SetLength(FUpdateBuffer,AUpdOrder+1);
+
+      FCurrentUpdateBuffer:=AUpdOrder;
+
+      FFilterBuffer:=IntAllocRecordBuffer;
+      fillchar(FFilterBuffer^,FNullmaskSize,0);
+      FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer := FFilterBuffer;
+      FDatasetReader.RestoreRecord(self);
+
+      FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind:= ukDelete;
+      FIndexes[0].StoreSpareRecIntoBookmark(@FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData);
+
+      AddRecordBuffer:=False;
+      end
+    else
+      AddRecordBuffer:=True;
 
     if AddRecordBuffer then
       begin
@@ -2534,35 +2556,6 @@ begin
     inc(EntryNr);
     end;
 
-  // Iterate through the ChangeLog list and add modifications to he update buffer
-  for i := 0 to length(ChangeLog)-1 do
-    begin
-    FCurrentUpdateBuffer:=Length(FUpdateBuffer);
-    setlength(FUpdateBuffer,FCurrentUpdateBuffer+1);
-    case ChangeLog[i].UpdateKind of
-      ukDelete : begin
-                 FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind:=ukDelete;
-                 FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData:=ChangeLogInfo[i].Bookmark;
-                 FDatasetReader.GotoElement(ChangeLogInfo[i].FirstChangeNode);
-                 FDatasetReader.RestoreRecord(self);
-                 FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer:=IntAllocRecordBuffer;
-                 move(findexes[0].SpareBuffer^,FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer^,FRecordSize);
-                 end;
-      ukModify : begin
-                 FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind:=ukModify;
-                 FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData:=ChangeLogInfo[i].Bookmark;
-                 FDatasetReader.GotoElement(ChangeLogInfo[i].SecondChangeNode);
-                 FDatasetReader.RestoreRecord(self);
-                 FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer:=IntAllocRecordBuffer;
-                 move(findexes[0].SpareBuffer^,FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer^,FRecordSize);
-                 end;
-      ukInsert : begin
-                 FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind:=ukInsert;
-                 FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData:=ChangeLogInfo[i].Bookmark;
-                 FDatasetReader.GotoElement(ChangeLogInfo[i].FirstChangeNode);
-                 end;
-    end; {case}
-    end;
   RestoreState(StoreState);
   FIndexes[0].SetToFirstRecord;
   FAllPacketsFetched:=True;
@@ -2820,6 +2813,7 @@ end;
 
 constructor TArrayBufIndex.Create(const ADataset: TBufDataset);
 begin
+  Inherited create(ADataset);
   FInitialBuffers:=10000;
   FGrowBuffer:=1000;
 end;
@@ -2993,6 +2987,27 @@ end;
 
 { TDataPacketReader }
 
+class function TDataPacketReader.RowStateToByte(const ARowState: TRowState
+  ): byte;
+var RowStateInt : Byte;
+begin
+  RowStateInt:=0;
+  if rsvOriginal in ARowState then RowStateInt := RowStateInt+1;
+  if rsvDeleted in ARowState then RowStateInt := RowStateInt+2;
+  if rsvInserted in ARowState then RowStateInt := RowStateInt+4;
+  if rsvUpdated in ARowState then RowStateInt := RowStateInt+8;
+  Result := RowStateInt;
+end;
+
+class function TDataPacketReader.ByteToRowState(const AByte: Byte): TRowState;
+begin
+  result := [];
+  if (AByte and 1)=1 then Result := Result+[rsvOriginal];
+  if (AByte and 2)=2 then Result := Result+[rsvDeleted];
+  if (AByte and 4)=4 then Result := Result+[rsvInserted];
+  if (AByte and 8)=8 then Result := Result+[rsvUpdated];
+end;
+
 constructor TDataPacketReader.create(AStream: TStream);
 begin
   FStream := AStream;
@@ -3044,17 +3059,20 @@ begin
     end;
 end;
 
-procedure TFpcBinaryDatapacketReader.GetRecordUpdState(var AIsUpdate,
-  AAddRecordBuffer, AIsFirstEntry: boolean);
+function TFpcBinaryDatapacketReader.GetRecordRowState(out AUpdOrder : Integer) : TRowState;
+var Buf : byte;
 begin
-  AIsUpdate:=False;
-  AAddRecordBuffer:=True;
+  Stream.Read(Buf,1);
+  Result := ByteToRowState(Buf);
+  if Result<>[] then
+    Stream.ReadBuffer(AUpdOrder,sizeof(integer))
+  else
+    AUpdOrder := 0;
 end;
 
-procedure TFpcBinaryDatapacketReader.EndStoreRecord(
-  const AChangeLog: TChangeLogEntryArr);
+procedure TFpcBinaryDatapacketReader.EndStoreRecord;
 begin
-//  inherited EndStoreRecord(AChangeLog);
+//  Do nothing
 end;
 
 function TFpcBinaryDatapacketReader.GetCurrentRecord: boolean;
@@ -3070,18 +3088,17 @@ end;
 
 procedure TFpcBinaryDatapacketReader.GotoElement(const AnElement: pointer);
 begin
-//  inherited GotoElement(AnElement);
+//  Do nothing
 end;
 
-procedure TFpcBinaryDatapacketReader.InitLoadRecords(
-  var AChangeLog: TChangeLogEntryArr);
+procedure TFpcBinaryDatapacketReader.InitLoadRecords;
 begin
-  SetLength(AChangeLog,0);
+//  SetLength(AChangeLog,0);
 end;
 
 function TFpcBinaryDatapacketReader.GetCurrentElement: pointer;
 begin
-//  Result:=inherited GetCurrentElement;
+//  Do nothing
 end;
 
 procedure TFpcBinaryDatapacketReader.RestoreRecord(ADataset: TBufDataset);
@@ -3090,10 +3107,13 @@ begin
 end;
 
 procedure TFpcBinaryDatapacketReader.StoreRecord(ADataset: TBufDataset;
-  RowState: TRowState);
+  ARowState: TRowState; AUpdOrder : integer);
 begin
   // Ugly because private members of ADataset are used...
   Stream.WriteByte($fe);
+  Stream.WriteByte(RowStateToByte(ARowState));
+  if ARowState<>[] then
+    Stream.WriteBuffer(AUpdOrder,sizeof(integer));
   Stream.WriteBuffer(ADataset.GetCurrentBuffer^,ADataset.FRecordSize);
 end;