Browse Source

* Started adding an array-approach to the already existing double-linked list mechanism in TBufDataset. The list based on an array can be enabled with the ARRAYBUF define

git-svn-id: trunk@9298 -
joost 17 years ago
parent
commit
96fe8e196a
2 changed files with 339 additions and 15 deletions
  1. 338 15
      packages/fcl-db/src/base/bufdataset.pas
  2. 1 0
      packages/fcl-db/src/base/dbconst.pas

+ 338 - 15
packages/fcl-db/src/base/bufdataset.pas

@@ -16,6 +16,7 @@
 
 
 unit BufDataset;
 unit BufDataset;
 
 
+{ $DEFINE ARRAYBUF}
 {$mode objfpc}
 {$mode objfpc}
 {$h+}
 {$h+}
 
 
@@ -62,14 +63,38 @@ type
 
 
   PBufBookmark = ^TBufBookmark;
   PBufBookmark = ^TBufBookmark;
   TBufBookmark = record
   TBufBookmark = record
+{$IFDEF ARRAYBUF}
+    BookmarkData : integer;
+    BookMarkBuf  : Pointer;
+{$ELSE}
     BookmarkData : PBufRecLinkItem;
     BookmarkData : PBufRecLinkItem;
+{$ENDIF}
     BookmarkFlag : TBookmarkFlag;
     BookmarkFlag : TBookmarkFlag;
   end;
   end;
 
 
-  PRecUpdateBuffer = ^TRecUpdateBuffer;
   TRecUpdateBuffer = record
   TRecUpdateBuffer = record
     UpdateKind         : TUpdateKind;
     UpdateKind         : TUpdateKind;
+{$IFDEF ARRAYBUF}
+{  BookMarkData:
+     - Is -1 if the update has canceled out. For example: a appended record has been deleted again
+     - If UpdateKind is ukInsert it contains a bookmark to the new created record
+     - If UpdateKind is ukModify it contains a bookmark to the record with the new data
+     - If UpdateKind is ukDelete it contains a bookmark to the record just after the deleted record
+}
+    Bookmark           : TBufBookmark;
+{$ELSE}
+{  BookMarkData:
+     - Is nil if the update has canceled out. For example: a appended record has been deleted again
+     - If UpdateKind is ukInsert it contains the PBufRecLinkItem of the created record
+     - If UpdateKind is ukModify it contains the PBufRecLinkItem of the record with the new data
+     - If UpdateKind is ukDelete it contains the PBufRecLinkItem of the deleted record
+}
     BookmarkData       : pointer;
     BookmarkData       : pointer;
+{$ENDIF}
+{  OldValuesBuffer:
+     - If UpdateKind is ukModify it contains a record-buffer which contains the old data
+     - If UpdateKind is ukDelete it contains the PBufRecLinkItem of the deleted record
+}
     OldValuesBuffer    : pchar;
     OldValuesBuffer    : pchar;
   end;
   end;
 
 
@@ -83,12 +108,21 @@ type
 
 
   TBufDataset = class(TDBDataSet)
   TBufDataset = class(TDBDataSet)
   private
   private
-    FIndexesCount   : integer;
-    FCurrentIndex   : integer;
-  
+{$IFDEF ARRAYBUF}
+    FCurrentRecInd  : integer;
+    FRecordArray    : array of Pointer;
+    FLastRecInd     : integer;
+    
+    FInitialBuffers : integer;
+    FGrowBuffer     : integer;
+{$ELSE}
     FCurrentRecBuf  : PBufRecLinkItem;
     FCurrentRecBuf  : PBufRecLinkItem;
     FLastRecBuf     : PBufRecLinkItem;
     FLastRecBuf     : PBufRecLinkItem;
     FFirstRecBuf    : PBufRecLinkItem;
     FFirstRecBuf    : PBufRecLinkItem;
+{$ENDIF ARRAYBUF}
+
+    FIndexesCount   : integer;
+    FCurrentIndex   : integer;
 
 
     FLastRecBufs    : array of PBufRecLinkItem;
     FLastRecBufs    : array of PBufRecLinkItem;
     FFirstRecBufs   : array of PBufRecLinkItem;
     FFirstRecBufs   : array of PBufRecLinkItem;
@@ -122,6 +156,9 @@ type
     function  IntAllocRecordBuffer: PChar;
     function  IntAllocRecordBuffer: PChar;
     procedure DoFilterRecord(var Acceptable: Boolean);
     procedure DoFilterRecord(var Acceptable: Boolean);
     procedure ParseFilter(const AFilter: string);
     procedure ParseFilter(const AFilter: string);
+{$IFDEF ARRAYBUF}
+    Function GetRecordFromBookmark(ABookmark: TBufBookmark) : integer;
+{$ENDIF}
   protected
   protected
     function GetNewBlobBuffer : PBlobBuffer;
     function GetNewBlobBuffer : PBlobBuffer;
     function GetNewWriteBlobBuffer : PBlobBuffer;
     function GetNewWriteBlobBuffer : PBlobBuffer;
@@ -194,11 +231,23 @@ uses variants, dbconst;
 constructor TBufDataset.Create(AOwner : TComponent);
 constructor TBufDataset.Create(AOwner : TComponent);
 begin
 begin
   Inherited Create(AOwner);
   Inherited Create(AOwner);
+{$IFDEF ARRAYBUF}
+  FRecordArray:=nil;
+  FCurrentRecInd:=-1;
+  FLastRecInd:=-1;
+
+  FInitialBuffers:=10000;
+  FGrowBuffer:=1000;
+  
+  setlength(FRecordArray,FInitialBuffers);
+{$ELSE}
+
   FIndexesCount:=2;
   FIndexesCount:=2;
   FCurrentIndex:=0;
   FCurrentIndex:=0;
   
   
   setlength(FFirstRecBufs,FIndexesCount);
   setlength(FFirstRecBufs,FIndexesCount);
   SetLength(FLastRecBufs,FIndexesCount);
   SetLength(FLastRecBufs,FIndexesCount);
+{$ENDIF}
 
 
   SetLength(FUpdateBuffer,0);
   SetLength(FUpdateBuffer,0);
   SetLength(FBlobBuffers,0);
   SetLength(FBlobBuffers,0);
@@ -227,7 +276,11 @@ end;
 function TBufDataset.intAllocRecordBuffer: PChar;
 function TBufDataset.intAllocRecordBuffer: PChar;
 begin
 begin
   // Note: Only the internal buffers of TDataset provide bookmark information
   // Note: Only the internal buffers of TDataset provide bookmark information
+{$IFDEF ARRAYBUF}
+  result := AllocMem(FRecordsize);
+{$ELSE}
   result := AllocMem(FRecordsize+sizeof(TBufRecLinkItem)*FIndexesCount);
   result := AllocMem(FRecordsize+sizeof(TBufRecLinkItem)*FIndexesCount);
+{$ENDIF}
 end;
 end;
 
 
 function TBufDataset.AllocRecordBuffer: PChar;
 function TBufDataset.AllocRecordBuffer: PChar;
@@ -250,9 +303,15 @@ begin
 
 
   FBRecordcount := 0;
   FBRecordcount := 0;
 
 
+{$IFNDEF ARRAYBUF}
   FFirstRecBuf := pointer(IntAllocRecordBuffer);
   FFirstRecBuf := pointer(IntAllocRecordBuffer);
   FLastRecBuf := FFirstRecBuf;
   FLastRecBuf := FFirstRecBuf;
   FCurrentRecBuf := FLastRecBuf;
   FCurrentRecBuf := FLastRecBuf;
+{$ELSE}
+  FLastRecInd := 0;
+  FCurrentRecInd := 0;
+  FRecordArray[0]:=IntAllocRecordBuffer;
+{$ENDIF}
 
 
   FAllPacketsFetched := False;
   FAllPacketsFetched := False;
 
 
@@ -275,6 +334,11 @@ var pc : pchar;
 
 
 begin
 begin
   FOpen:=False;
   FOpen:=False;
+{$IFDEF ARRAYBUF}
+  for r := 0 to FLastRecInd do
+    FreeRecordBuffer(FRecordArray[r]);
+  SetLength(FRecordArray,FInitialBuffers);
+{$ELSE}
   FCurrentRecBuf := FFirstRecBuf;
   FCurrentRecBuf := FFirstRecBuf;
   while assigned(FCurrentRecBuf) do
   while assigned(FCurrentRecBuf) do
     begin
     begin
@@ -282,12 +346,17 @@ begin
     FCurrentRecBuf := FCurrentRecBuf^.next;
     FCurrentRecBuf := FCurrentRecBuf^.next;
     FreeRecordBuffer(pc);
     FreeRecordBuffer(pc);
     end;
     end;
+{$ENDIF}
 
 
   if Length(FUpdateBuffer) > 0 then
   if Length(FUpdateBuffer) > 0 then
     begin
     begin
     for r := 0 to length(FUpdateBuffer)-1 do with FUpdateBuffer[r] do
     for r := 0 to length(FUpdateBuffer)-1 do with FUpdateBuffer[r] do
       begin
       begin
+{$IFDEF ARRAYBUF}
+      if Bookmark.BookmarkData > 0 then
+{$ELSE}
       if assigned(BookmarkData) then
       if assigned(BookmarkData) then
+{$ENDIF}
         FreeRecordBuffer(OldValuesBuffer);
         FreeRecordBuffer(OldValuesBuffer);
       end;
       end;
     end;
     end;
@@ -300,8 +369,10 @@ begin
 
 
   SetLength(FBlobBuffers,0);
   SetLength(FBlobBuffers,0);
   SetLength(FUpdateBlobBuffers,0);
   SetLength(FUpdateBlobBuffers,0);
-
+{$IFNDEF ARRAYBUF}
   FFirstRecBuf:= nil;
   FFirstRecBuf:= nil;
+{$ENDIF}
+
   SetLength(FFieldBufPositions,0);
   SetLength(FFieldBufPositions,0);
 
 
   if assigned(FParser) then FreeAndNil(FParser);
   if assigned(FParser) then FreeAndNil(FParser);
@@ -311,16 +382,26 @@ procedure TBufDataset.InternalFirst;
 begin
 begin
 // if FCurrentRecBuf = FLastRecBuf then the dataset is just opened and empty
 // if FCurrentRecBuf = FLastRecBuf then the dataset is just opened and empty
 // in which case InternalFirst should do nothing (bug 7211)
 // in which case InternalFirst should do nothing (bug 7211)
+{$IFDEF ARRAYBUF}
+  if FCurrentRecInd <> FLastRecInd then
+    FCurrentRecInd := -1;
+{$ELSE}
   if FCurrentRecBuf <> FLastRecBuf then
   if FCurrentRecBuf <> FLastRecBuf then
     FCurrentRecBuf := nil;
     FCurrentRecBuf := nil;
+{$ENDIF}
 end;
 end;
 
 
 procedure TBufDataset.InternalLast;
 procedure TBufDataset.InternalLast;
 begin
 begin
   repeat
   repeat
   until (getnextpacket < FPacketRecords) or (FPacketRecords = -1);
   until (getnextpacket < FPacketRecords) or (FPacketRecords = -1);
+{$IFDEF ARRAYBUF}
+  if FLastRecInd <> 0 then
+    FCurrentRecInd := FLastRecInd;
+{$ELSE}
   if FLastRecBuf <> FFirstRecBuf then
   if FLastRecBuf <> FFirstRecBuf then
     FCurrentRecBuf := FLastRecBuf;
     FCurrentRecBuf := FLastRecBuf;
+{$ENDIF}
 end;
 end;
 
 
 procedure unSetFieldIsNull(NullMask : pbyte;x : longint); //inline;
 procedure unSetFieldIsNull(NullMask : pbyte;x : longint); //inline;
@@ -350,6 +431,12 @@ begin
   Acceptable := True;
   Acceptable := True;
   case GetMode of
   case GetMode of
     gmPrior :
     gmPrior :
+{$IFDEF ARRAYBUF}
+      if FCurrentRecInd=0 then
+        Result := grBOF
+      else
+        Dec(FCurrentRecInd);
+{$ELSE}
       if not assigned(FCurrentRecBuf[FCurrentIndex].prior) then
       if not assigned(FCurrentRecBuf[FCurrentIndex].prior) then
         begin
         begin
         Result := grBOF;
         Result := grBOF;
@@ -358,10 +445,38 @@ begin
         begin
         begin
         FCurrentRecBuf := FCurrentRecBuf[FCurrentIndex].prior;
         FCurrentRecBuf := FCurrentRecBuf[FCurrentIndex].prior;
         end;
         end;
+{$ENDIF}
     gmCurrent :
     gmCurrent :
+{$IFDEF ARRAYBUF}
+      if FCurrentRecInd = FLastRecInd then
+        Result := grError;
+{$ELSE}
       if FCurrentRecBuf = FLastRecBuf then
       if FCurrentRecBuf = FLastRecBuf then
         Result := grError;
         Result := grError;
+{$ENDIF}
     gmNext :
     gmNext :
+{$IFDEF ARRAYBUF}
+      if FCurrentRecInd = FLastRecInd then // Dataset is empty (just opened)
+        begin
+        if getnextpacket = 0 then result := grEOF;
+        end
+      else if FCurrentRecInd = -1 then FCurrentRecInd := 0
+      else if FCurrentRecInd = FLastRecInd-1 then
+        begin
+        if getnextpacket > 0 then
+          begin
+          inc(FCurrentRecInd);
+          end
+        else
+          begin
+          result:=grEOF;
+          end
+        end
+      else
+        begin
+        inc(FCurrentRecInd);
+        end;
+{$ELSE}
       if FCurrentRecBuf = FLastRecBuf then // Dataset is empty (just opened)
       if FCurrentRecBuf = FLastRecBuf then // Dataset is empty (just opened)
         begin
         begin
         if getnextpacket = 0 then result := grEOF;
         if getnextpacket = 0 then result := grEOF;
@@ -382,6 +497,7 @@ begin
         begin
         begin
         FCurrentRecBuf := FCurrentRecBuf[FCurrentIndex].next;
         FCurrentRecBuf := FCurrentRecBuf[FCurrentIndex].next;
         end;
         end;
+{$ENDIF}
   end;
   end;
 
 
   if Result = grOK then
   if Result = grOK then
@@ -389,10 +505,20 @@ begin
 
 
     with PBufBookmark(Buffer + FRecordSize)^ do
     with PBufBookmark(Buffer + FRecordSize)^ do
       begin
       begin
+{$IFDEF ARRAYBUF}
+      BookmarkData := FCurrentRecInd;
+      BookMarkBuf := FRecordArray[FCurrentRecInd];
+{$ELSE}
       BookmarkData := FCurrentRecBuf;
       BookmarkData := FCurrentRecBuf;
+{$ENDIF}
       BookmarkFlag := bfCurrent;
       BookmarkFlag := bfCurrent;
       end;
       end;
+{$IFDEF ARRAYBUF}
+    move((FRecordArray[FCurrentRecInd])^,buffer^,FRecordSize);
+{$ELSE}
     move((pointer(FCurrentRecBuf)+sizeof(TBufRecLinkItem)*FIndexesCount)^,buffer^,FRecordSize);
     move((pointer(FCurrentRecBuf)+sizeof(TBufRecLinkItem)*FIndexesCount)^,buffer^,FRecordSize);
+{$ENDIF}
+
     GetCalcFields(Buffer);
     GetCalcFields(Buffer);
 
 
     if Filtered then
     if Filtered then
@@ -416,28 +542,57 @@ end;
 function TBufDataset.GetRecordUpdateBuffer : boolean;
 function TBufDataset.GetRecordUpdateBuffer : boolean;
 
 
 var x : integer;
 var x : integer;
+{$IFDEF ARRAYBUF}
+    ABookmark : TBufBookmark;
+    CurrBuff  : Integer;
+{$ELSE}
     CurrBuff : PChar;
     CurrBuff : PChar;
+{$ENDIF}
+
+  function CompareBuf(const ABuf : integer) : boolean; inline;
+  
+  begin
+{$IFDEF ARRAYBUF}
+    result := (FUpdateBuffer[ABuf].Bookmark.BookMarkBuf<>nil) // Record is verwijderd, onmogelijk om UpdateBuffer te achterhalen.
+          and (GetRecordFromBookmark(FUpdateBuffer[ABuf].Bookmark) = CurrBuff);
+{$ELSE}
+    result := (FUpdateBuffer[ABuf].BookmarkData = CurrBuff);
+{$ENDIF}
+  end;
 
 
 begin
 begin
+{$IFDEF ARRAYBUF}
+  GetBookmarkData(ActiveBuffer,@ABookmark);
+  CurrBuff:=GetRecordFromBookmark(ABookmark);
+{$ELSE}
   GetBookmarkData(ActiveBuffer,@CurrBuff);
   GetBookmarkData(ActiveBuffer,@CurrBuff);
-  if (FCurrentUpdateBuffer >= length(FUpdateBuffer)) or (FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData <> CurrBuff) then
+{$ENDIF}
+  if (FCurrentUpdateBuffer >= length(FUpdateBuffer)) or not CompareBuf(FCurrentUpdateBuffer) then
    for x := 0 to high(FUpdateBuffer) do
    for x := 0 to high(FUpdateBuffer) do
-    if FUpdateBuffer[x].BookmarkData = CurrBuff then
+    if CompareBuf(x) then
       begin
       begin
       FCurrentUpdateBuffer := x;
       FCurrentUpdateBuffer := x;
       break;
       break;
       end;
       end;
-  Result := (FCurrentUpdateBuffer < length(FUpdateBuffer))  and (FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData = CurrBuff);
+  Result := (FCurrentUpdateBuffer < length(FUpdateBuffer))  and CompareBuf(FCurrentUpdateBuffer);
 end;
 end;
 
 
 procedure TBufDataset.InternalSetToRecord(Buffer: PChar);
 procedure TBufDataset.InternalSetToRecord(Buffer: PChar);
 begin
 begin
+{$IFDEF ARRAYBUF}
+  FCurrentRecInd:=GetRecordFromBookmark(PBufBookmark(Buffer + FRecordSize)^);
+{$ELSE}
   FCurrentRecBuf := PBufBookmark(Buffer + FRecordSize)^.BookmarkData;
   FCurrentRecBuf := PBufBookmark(Buffer + FRecordSize)^.BookmarkData;
+{$ENDIF}
 end;
 end;
 
 
 procedure TBufDataset.SetBookmarkData(Buffer: PChar; Data: Pointer);
 procedure TBufDataset.SetBookmarkData(Buffer: PChar; Data: Pointer);
 begin
 begin
+{$IFDEF ARRAYBUF}
+  PBufBookmark(Buffer + FRecordSize)^.BookmarkData := integer(Data^);
+{$ELSE}
   PBufBookmark(Buffer + FRecordSize)^.BookmarkData := pointer(Data^);
   PBufBookmark(Buffer + FRecordSize)^.BookmarkData := pointer(Data^);
+{$ENDIF}
 end;
 end;
 
 
 procedure TBufDataset.SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag);
 procedure TBufDataset.SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag);
@@ -447,7 +602,11 @@ end;
 
 
 procedure TBufDataset.GetBookmarkData(Buffer: PChar; Data: Pointer);
 procedure TBufDataset.GetBookmarkData(Buffer: PChar; Data: Pointer);
 begin
 begin
+{$IFDEF ARRAYBUF}
+  PBufBookmark(Data)^ := PBufBookmark(Buffer + FRecordSize)^;
+{$ELSE}
   pointer(Data^) := PBufBookmark(Buffer + FRecordSize)^.BookmarkData;
   pointer(Data^) := PBufBookmark(Buffer + FRecordSize)^.BookmarkData;
+{$ENDIF}
 end;
 end;
 
 
 function TBufDataset.GetBookmarkFlag(Buffer: PChar): TBookmarkFlag;
 function TBufDataset.GetBookmarkFlag(Buffer: PChar): TBookmarkFlag;
@@ -459,7 +618,11 @@ procedure TBufDataset.InternalGotoBookmark(ABookmark: Pointer);
 begin
 begin
   // note that ABookMark should be a PBufBookmark. But this way it can also be
   // note that ABookMark should be a PBufBookmark. But this way it can also be
   // a pointer to a TBufRecLinkItem
   // a pointer to a TBufRecLinkItem
+{$IFDEF ARRAYBUF}
+  FCurrentRecInd:=GetRecordFromBookmark(PBufBookmark(ABookmark)^);
+{$ELSE}
   FCurrentRecBuf := pointer(ABookmark^);
   FCurrentRecBuf := pointer(ABookmark^);
+{$ENDIF}
 end;
 end;
 
 
 function TBufDataset.getnextpacket : integer;
 function TBufDataset.getnextpacket : integer;
@@ -474,13 +637,25 @@ begin
     exit;
     exit;
     end;
     end;
   i := 0;
   i := 0;
+{$IFDEF ARRAYBUF}
+  pb := pchar(FRecordArray[FLastRecInd]);
+{$ELSE}
   pb := pchar(pointer(FLastRecBuf)+sizeof(TBufRecLinkItem)*FIndexesCount);
   pb := pchar(pointer(FLastRecBuf)+sizeof(TBufRecLinkItem)*FIndexesCount);
+{$ENDIF}
   while ((i < FPacketRecords) or (FPacketRecords = -1)) and (loadbuffer(pb) = grOk) do
   while ((i < FPacketRecords) or (FPacketRecords = -1)) and (loadbuffer(pb) = grOk) do
     begin
     begin
+{$IFDEF ARRAYBUF}
+    inc(FLastRecInd);
+    if FLastRecInd >= length(FRecordArray) then
+      SetLength(FRecordArray,length(FRecordArray)+FGrowBuffer);
+    FRecordArray[FLastRecInd]:=IntAllocRecordBuffer;
+    pb := pchar(FRecordArray[FLastRecInd]);
+{$ELSE}
     FLastRecBuf^.next := pointer(IntAllocRecordBuffer);
     FLastRecBuf^.next := pointer(IntAllocRecordBuffer);
     FLastRecBuf^.next^.prior := FLastRecBuf;
     FLastRecBuf^.next^.prior := FLastRecBuf;
     FLastRecBuf := FLastRecBuf^.next;
     FLastRecBuf := FLastRecBuf^.next;
     pb := pchar(pointer(FLastRecBuf)+sizeof(TBufRecLinkItem)*FIndexesCount);
     pb := pchar(pointer(FLastRecBuf)+sizeof(TBufRecLinkItem)*FIndexesCount);
+{$ENDIF}
     inc(i);
     inc(i);
     end;
     end;
   FBRecordCount := FBRecordCount + i;
   FBRecordCount := FBRecordCount + i;
@@ -639,7 +814,11 @@ begin
     exit;
     exit;
     end;
     end;
   if state = dsFilter then  // Set the value into the 'temporary' FLastRecBuf buffer for Locate and Lookup
   if state = dsFilter then  // Set the value into the 'temporary' FLastRecBuf buffer for Locate and Lookup
+{$IFDEF ARRAYBUF}
+    CurrBuff := FRecordArray[FLastRecInd]
+{$ELSE}
     CurrBuff := pointer(FLastRecBuf) + sizeof(TBufRecLinkItem)*FIndexesCount
     CurrBuff := pointer(FLastRecBuf) + sizeof(TBufRecLinkItem)*FIndexesCount
+{$ENDIF}
   else
   else
     CurrBuff := GetCurrentBuffer;
     CurrBuff := GetCurrentBuffer;
   If Field.Fieldno > 0 then // If = 0, then calculated field or something
   If Field.Fieldno > 0 then // If = 0, then calculated field or something
@@ -668,41 +847,66 @@ begin
 end;
 end;
 
 
 procedure TBufDataset.InternalDelete;
 procedure TBufDataset.InternalDelete;
-
+{$IFDEF ARRAYBUF}
+var ABookmark : TBufBookmark;
+{$ENDIF}
 begin
 begin
-  GetBookmarkData(ActiveBuffer,@FCurrentRecBuf);
-
+  InternalSetToRecord(ActiveBuffer);
+{$IFNDEF ARRAYBUF}
   if FCurrentRecBuf <> FFirstRecBuf then FCurrentRecBuf^.prior^.next := FCurrentRecBuf^.next
   if FCurrentRecBuf <> FFirstRecBuf then FCurrentRecBuf^.prior^.next := FCurrentRecBuf^.next
   else FFirstRecBuf := FCurrentRecBuf^.next;
   else FFirstRecBuf := FCurrentRecBuf^.next;
 
 
   FCurrentRecBuf^.next^.prior :=  FCurrentRecBuf^.prior;
   FCurrentRecBuf^.next^.prior :=  FCurrentRecBuf^.prior;
+{$ENDIF}
 
 
   if not GetRecordUpdateBuffer then
   if not GetRecordUpdateBuffer then
     begin
     begin
     FCurrentUpdateBuffer := length(FUpdateBuffer);
     FCurrentUpdateBuffer := length(FUpdateBuffer);
     SetLength(FUpdateBuffer,FCurrentUpdateBuffer+1);
     SetLength(FUpdateBuffer,FCurrentUpdateBuffer+1);
 
 
+{$IFDEF ARRAYBUF}
+    FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer := FRecordArray[FCurrentRecInd];
+    FUpdateBuffer[FCurrentUpdateBuffer].Bookmark.BookMarkBuf:=nil;
+    FUpdateBuffer[FCurrentUpdateBuffer].Bookmark.BookmarkData := FCurrentRecInd;
+{$ELSE}
     FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer := pchar(FCurrentRecBuf);
     FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer := pchar(FCurrentRecBuf);
     FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData := FCurrentRecBuf;
     FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData := FCurrentRecBuf;
 
 
     FCurrentRecBuf := FCurrentRecBuf^.next;
     FCurrentRecBuf := FCurrentRecBuf^.next;
+{$ENDIF}
     end
     end
   else
   else
     begin
     begin
     if FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind = ukModify then
     if FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind = ukModify then
       begin
       begin
+{$IFDEF ARRAYBUF}
+      FreeRecordBuffer(FRecordArray[FCurrentRecInd]);
+      FUpdateBuffer[FCurrentUpdateBuffer].Bookmark.BookmarkData := FCurrentRecInd;
+      FUpdateBuffer[FCurrentUpdateBuffer].Bookmark.BookMarkBuf := nil;
+{$ELSE}
       FCurrentRecBuf := FCurrentRecBuf^.next;
       FCurrentRecBuf := FCurrentRecBuf^.next;
       FreeRecordBuffer(pchar(FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData));
       FreeRecordBuffer(pchar(FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData));
       FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData := FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer;
       FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData := FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer;
+{$ENDIF}
       end
       end
     else
     else
       begin
       begin
+{$IFDEF ARRAYBUF}
+      FreeRecordBuffer(pchar(FRecordArray[GetRecordFromBookmark(FUpdateBuffer[FCurrentUpdateBuffer].Bookmark)]));
+      FUpdateBuffer[FCurrentUpdateBuffer].Bookmark.BookmarkData := -1;  //this 'disables' the updatebuffer
+{$ELSE}
       FCurrentRecBuf := FCurrentRecBuf^.next;
       FCurrentRecBuf := FCurrentRecBuf^.next;
       FreeRecordBuffer(pchar(FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData));
       FreeRecordBuffer(pchar(FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData));
       FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData := nil;  //this 'disables' the updatebuffer
       FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData := nil;  //this 'disables' the updatebuffer
+{$ENDIF}
       end;
       end;
     end;
     end;
 
 
+{$IFDEF ARRAYBUF}
+  Move(FRecordArray[FCurrentRecInd+1],FRecordArray[FCurrentRecInd],sizeof(Pointer)*(FLastRecInd-FCurrentRecInd));
+  dec(FLastRecInd);
+{$ENDIF}
+
   dec(FBRecordCount);
   dec(FBRecordCount);
   FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind := ukDelete;
   FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind := ukDelete;
 end;
 end;
@@ -717,6 +921,9 @@ end;
 procedure TBufDataset.CancelUpdates;
 procedure TBufDataset.CancelUpdates;
 
 
 var r              : Integer;
 var r              : Integer;
+{$IFDEF ARRAYBUF}
+    RecInd         : integer;
+{$ENDIF}
 
 
 begin
 begin
   CheckBrowseMode;
   CheckBrowseMode;
@@ -726,24 +933,46 @@ begin
     r := Length(FUpdateBuffer) -1;
     r := Length(FUpdateBuffer) -1;
     while r > -1 do with FUpdateBuffer[r] do
     while r > -1 do with FUpdateBuffer[r] do
       begin
       begin
+{$IFDEF ARRAYBUF}
+      if FUpdateBuffer[r].Bookmark.BookmarkData <> -1 then
+{$ELSE}
       if assigned(FUpdateBuffer[r].BookmarkData) then
       if assigned(FUpdateBuffer[r].BookmarkData) then
+{$ENDIF}
         begin
         begin
         if UpdateKind = ukModify then
         if UpdateKind = ukModify then
           begin
           begin
+{$IFDEF ARRAYBUF}
+          FreeRecordBuffer(FRecordArray[Bookmark.BookmarkData]);
+          FRecordArray[Bookmark.BookmarkData] := OldValuesBuffer;
+{$ELSE}
           move(pchar(OldValuesBuffer+sizeof(TBufRecLinkItem)*FIndexesCount)^,pchar(BookmarkData+sizeof(TBufRecLinkItem)*FIndexesCount)^,FRecordSize);
           move(pchar(OldValuesBuffer+sizeof(TBufRecLinkItem)*FIndexesCount)^,pchar(BookmarkData+sizeof(TBufRecLinkItem)*FIndexesCount)^,FRecordSize);
           FreeRecordBuffer(OldValuesBuffer);
           FreeRecordBuffer(OldValuesBuffer);
+{$ENDIF}
           end
           end
         else if UpdateKind = ukDelete then
         else if UpdateKind = ukDelete then
           begin
           begin
+{$IFDEF ARRAYBUF}
+          RecInd := GetRecordFromBookmark(Bookmark);
+          move(FRecordArray[RecInd],FRecordArray[RecInd+1],sizeof(Pointer)*(FLastRecInd-RecInd+1));
+          FRecordArray[RecInd] := OldValuesBuffer;
+          inc(FLastRecInd);
+{$ELSE}
           if assigned(PBufRecLinkItem(BookmarkData)^.prior) then  // or else it was the first record
           if assigned(PBufRecLinkItem(BookmarkData)^.prior) then  // or else it was the first record
             PBufRecLinkItem(BookmarkData)^.prior^.next := BookmarkData
             PBufRecLinkItem(BookmarkData)^.prior^.next := BookmarkData
           else
           else
             FFirstRecBuf := BookmarkData;
             FFirstRecBuf := BookmarkData;
           PBufRecLinkItem(BookmarkData)^.next^.prior := BookmarkData;
           PBufRecLinkItem(BookmarkData)^.next^.prior := BookmarkData;
+{$ENDIF}
           inc(FBRecordCount);
           inc(FBRecordCount);
           end
           end
         else if UpdateKind = ukInsert then
         else if UpdateKind = ukInsert then
           begin
           begin
+{$IFDEF ARRAYBUF}
+          RecInd := GetRecordFromBookmark(Bookmark);
+          FreeRecordBuffer(FRecordArray[RecInd]);
+          move(FRecordArray[RecInd+1],FRecordArray[RecInd],sizeof(Pointer)*(FLastRecInd-RecInd));
+          dec(FLastRecInd);
+{$ELSE}
           if assigned(PBufRecLinkItem(BookmarkData)^.prior) then // or else it was the first record
           if assigned(PBufRecLinkItem(BookmarkData)^.prior) then // or else it was the first record
             PBufRecLinkItem(BookmarkData)^.prior^.next := PBufRecLinkItem(BookmarkData)^.next
             PBufRecLinkItem(BookmarkData)^.prior^.next := PBufRecLinkItem(BookmarkData)^.next
           else
           else
@@ -752,6 +981,7 @@ begin
           // resync won't work if the currentbuffer is freed...
           // resync won't work if the currentbuffer is freed...
           if FCurrentRecBuf = BookmarkData then FCurrentRecBuf := FCurrentRecBuf^.next;
           if FCurrentRecBuf = BookmarkData then FCurrentRecBuf := FCurrentRecBuf^.next;
           FreeRecordBuffer(BookmarkData);
           FreeRecordBuffer(BookmarkData);
+{$ENDIF}
           dec(FBRecordCount);
           dec(FBRecordCount);
           end;
           end;
         end;
         end;
@@ -784,6 +1014,9 @@ var r            : Integer;
     AUpdateErr   : EUpdateError;
     AUpdateErr   : EUpdateError;
 
 
 begin
 begin
+{$IFDEF ARRAYBUF}
+  DatabaseError('ApplyUpdates is not supported');
+{$ELSE}
   CheckBrowseMode;
   CheckBrowseMode;
 
 
   StoreRecBuf := FCurrentRecBuf;
   StoreRecBuf := FCurrentRecBuf;
@@ -857,6 +1090,7 @@ begin
     FCurrentRecBuf := StoreRecBuf;
     FCurrentRecBuf := StoreRecBuf;
     Resync([]);
     Resync([]);
   end;
   end;
+{$ENDIF}
 end;
 end;
 
 
 
 
@@ -902,13 +1136,24 @@ begin
     begin
     begin
     if GetBookmarkFlag(ActiveBuffer) = bfEOF then
     if GetBookmarkFlag(ActiveBuffer) = bfEOF then
       // Append
       // Append
+{$IFDEF ARRAYBUF}
+      FCurrentRecInd := FLastRecInd
+{$ELSE}
       FCurrentRecBuf := FLastRecBuf
       FCurrentRecBuf := FLastRecBuf
+{$ENDIF}
     else
     else
       // The active buffer is the newly created TDataset record,
       // The active buffer is the newly created TDataset record,
       // from which the bookmark is set to the record where the new record should be
       // from which the bookmark is set to the record where the new record should be
       // inserted
       // inserted
-      GetBookmarkData(ActiveBuffer,@FCurrentRecBuf);
-
+      InternalSetToRecord(ActiveBuffer);
+
+{$IFDEF ARRAYBUF}
+    inc(FLastRecInd);
+    if FLastRecInd >= length(FRecordArray) then
+      SetLength(FRecordArray,length(FRecordArray)+FGrowBuffer);
+    Move(FRecordArray[FCurrentRecInd],FRecordArray[FCurrentRecInd+1],sizeof(Pointer)*(FLastRecInd-FCurrentRecInd));
+    FRecordArray[FCurrentRecInd]:=pointer(IntAllocRecordBuffer);
+{$ELSE}
     // Create the new record buffer
     // Create the new record buffer
     tmpRecBuffer := FCurrentRecBuf^.prior;
     tmpRecBuffer := FCurrentRecBuf^.prior;
 
 
@@ -922,40 +1167,58 @@ begin
       end
       end
     else
     else
       FFirstRecBuf := FCurrentRecBuf;
       FFirstRecBuf := FCurrentRecBuf;
+{$ENDIF}
 
 
     // Link the newly created record buffer to the newly created TDataset record
     // Link the newly created record buffer to the newly created TDataset record
     with PBufBookmark(ActiveBuffer + FRecordSize)^ do
     with PBufBookmark(ActiveBuffer + FRecordSize)^ do
       begin
       begin
+{$IFDEF ARRAYBUF}
+      BookmarkData := FCurrentRecInd;
+{$ELSE}
       BookmarkData := FCurrentRecBuf;
       BookmarkData := FCurrentRecBuf;
+{$ENDIF}
       BookmarkFlag := bfInserted;
       BookmarkFlag := bfInserted;
       end;
       end;
       
       
     inc(FBRecordCount);
     inc(FBRecordCount);
     end
     end
   else
   else
-    GetBookmarkData(ActiveBuffer,@FCurrentRecBuf);
+    InternalSetToRecord(ActiveBuffer);
 
 
   if not GetRecordUpdateBuffer then
   if not GetRecordUpdateBuffer then
     begin
     begin
     FCurrentUpdateBuffer := length(FUpdateBuffer);
     FCurrentUpdateBuffer := length(FUpdateBuffer);
     SetLength(FUpdateBuffer,FCurrentUpdateBuffer+1);
     SetLength(FUpdateBuffer,FCurrentUpdateBuffer+1);
 
 
+{$IFDEF ARRAYBUF}
+    FUpdateBuffer[FCurrentUpdateBuffer].Bookmark.BookmarkData := FCurrentRecInd;
+    FUpdateBuffer[FCurrentUpdateBuffer].Bookmark.BookMarkBuf := FRecordArray[FCurrentRecInd];
+{$ELSE}
     FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData := FCurrentRecBuf;
     FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData := FCurrentRecBuf;
+{$ENDIF}
 
 
     if state = dsEdit then
     if state = dsEdit then
       begin
       begin
       // Update the oldvalues-buffer
       // Update the oldvalues-buffer
       FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer := intAllocRecordBuffer;
       FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer := intAllocRecordBuffer;
+{$IFDEF ARRAYBUF}
+      move(FRecordArray[FCurrentRecInd]^,FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer^,FRecordSize);
+{$ELSE}
       move(FCurrentRecBuf^,FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer^,FRecordSize+sizeof(TBufRecLinkItem)*FIndexesCount);
       move(FCurrentRecBuf^,FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer^,FRecordSize+sizeof(TBufRecLinkItem)*FIndexesCount);
+{$ENDIF}
       FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind := ukModify;
       FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind := ukModify;
       end
       end
     else
     else
       FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind := ukInsert;
       FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind := ukInsert;
     end;
     end;
 
 
+{$IFDEF ARRAYBUF}
+  move(ActiveBuffer^,FRecordArray[FCurrentRecInd]^,FRecordSize);
+{$ELSE}
   CurrBuff := pchar(FCurrentRecBuf);
   CurrBuff := pchar(FCurrentRecBuf);
   inc(Currbuff,sizeof(TBufRecLinkItem)*FIndexesCount);
   inc(Currbuff,sizeof(TBufRecLinkItem)*FIndexesCount);
   move(ActiveBuffer^,CurrBuff^,FRecordSize);
   move(ActiveBuffer^,CurrBuff^,FRecordSize);
+{$ENDIF}
 end;
 end;
 
 
 procedure TBufDataset.CalcRecordSize;
 procedure TBufDataset.CalcRecordSize;
@@ -996,8 +1259,13 @@ end;
 
 
 procedure TBufDataset.SetRecNo(Value: Longint);
 procedure TBufDataset.SetRecNo(Value: Longint);
 
 
-var recnr        : integer;
+var
+{$IFDEF ARRAYBUF}
+    ABookMark    : TBufBookmark;
+{$ELSE}
+    recnr        : integer;
     TmpRecBuffer : PBufRecLinkItem;
     TmpRecBuffer : PBufRecLinkItem;
+{$ENDIF}
 
 
 begin
 begin
   checkbrowsemode;
   checkbrowsemode;
@@ -1010,10 +1278,16 @@ begin
       exit;
       exit;
       end;
       end;
     end;
     end;
+{$IFDEF ARRAYBUF}
+  ABookMark.BookMarkBuf:=nil;
+  ABookMark.BookmarkData:=Value-1;
+  GotoBookmark(@ABookMark);
+{$ELSE}
   TmpRecBuffer := FFirstRecBuf;
   TmpRecBuffer := FFirstRecBuf;
   for recnr := 1 to value-1 do
   for recnr := 1 to value-1 do
     TmpRecBuffer := TmpRecBuffer^.next;
     TmpRecBuffer := TmpRecBuffer^.next;
   GotoBookmark(@TmpRecBuffer);
   GotoBookmark(@TmpRecBuffer);
+{$ENDIF}
 end;
 end;
 
 
 function TBufDataset.GetRecNo: Longint;
 function TBufDataset.GetRecNo: Longint;
@@ -1022,12 +1296,20 @@ Var SearchRecBuffer : PBufRecLinkItem;
     TmpRecBuffer    : PBufRecLinkItem;
     TmpRecBuffer    : PBufRecLinkItem;
     recnr           : integer;
     recnr           : integer;
     abuf            : PChar;
     abuf            : PChar;
+{$IFDEF ARRAYBUF}
+    ABookMark       : TBufBookmark;
+{$ENDIF}
 
 
 begin
 begin
   abuf := GetCurrentBuffer;
   abuf := GetCurrentBuffer;
   // If abuf isn't assigned, the recordset probably isn't opened.
   // If abuf isn't assigned, the recordset probably isn't opened.
   if assigned(abuf) and (FBRecordCount>0) and (state <> dsInsert) then
   if assigned(abuf) and (FBRecordCount>0) and (state <> dsInsert) then
     begin
     begin
+{$IFDEF ARRAYBUF}
+    GetBookmarkData(abuf,@ABookMark);
+    recnr:=GetRecordFromBookmark(ABookMark);
+    inc(recnr);
+{$ELSE}
     GetBookmarkData(abuf,@SearchRecBuffer);
     GetBookmarkData(abuf,@SearchRecBuffer);
     TmpRecBuffer := FFirstRecBuf;
     TmpRecBuffer := FFirstRecBuf;
     recnr := 1;
     recnr := 1;
@@ -1036,6 +1318,7 @@ begin
       inc(recnr);
       inc(recnr);
       TmpRecBuffer := TmpRecBuffer^.next;
       TmpRecBuffer := TmpRecBuffer^.next;
       end;
       end;
+{$ENDIF}
     result := recnr;
     result := recnr;
     end
     end
   else result := 0;
   else result := 0;
@@ -1242,6 +1525,7 @@ var ALinkItem,
     ANewLinkItem : PBufRecLinkItem;
     ANewLinkItem : PBufRecLinkItem;
 
 
 begin
 begin
+{$IFNDEF ARRAYBUF}
   ALinkItem:=FLastRecBuf[0].prior;
   ALinkItem:=FLastRecBuf[0].prior;
   ANewLinkItem:=FLastRecBuf[0].prior;
   ANewLinkItem:=FLastRecBuf[0].prior;
 
 
@@ -1268,6 +1552,7 @@ begin
   FCurrentRecBuf:=FFirstRecBuf;
   FCurrentRecBuf:=FFirstRecBuf;
 
 
   Resync([rmExact,rmCenter]);
   Resync([rmExact,rmCenter]);
+{$ENDIF}
 end;
 end;
 
 
 
 
@@ -1292,6 +1577,36 @@ begin
   end;
   end;
 end;
 end;
 
 
+{$IFDEF ARRAYBUF}
+function TBufDataset.GetRecordFromBookmark(ABookMark: TBufBookmark) : integer;
+begin
+  // ABookmark.BookMarkBuf is nil if SetRecNo calls GotoBookmark
+  if (ABookmark.BookMarkBuf<>nil) and (FRecordArray[ABookmark.BookmarkData]<>ABookmark.BookMarkBuf) then
+    begin
+    if ABookmark.BookmarkData > 2 then
+      Result := ABookmark.BookmarkData-2
+    else
+      Result := 0;
+
+    while (Result<FLastRecInd) do
+      begin
+      if (FRecordArray[Result] = ABookmark.BookMarkBuf) then exit;
+      inc(Result);
+      end;
+
+    Result:=0;
+    while (Result<ABookmark.BookmarkData) do
+      begin
+      if (FRecordArray[Result] = ABookmark.BookMarkBuf) then exit;
+      inc(Result);
+      end;
+
+    DatabaseError(SInvalidBookmark,self)
+    end
+  else
+    Result := ABookmark.BookmarkData;
+end;
+{$ENDIF}
 
 
 Function TBufDataset.Locate(const KeyFields: string; const KeyValues: Variant; options: TLocateOptions) : boolean;
 Function TBufDataset.Locate(const KeyFields: string; const KeyValues: Variant; options: TLocateOptions) : boolean;
 
 
@@ -1335,6 +1650,9 @@ var keyfield    : TField;     // Field to search in
     SaveState   : TDataSetState;
     SaveState   : TDataSetState;
 
 
 begin
 begin
+{$IFDEF ARRAYBUF}
+  DatabaseError('Locate is not supported');
+{$ELSE}
 // For now it is only possible to search in one field at the same time
 // For now it is only possible to search in one field at the same time
   result := False;
   result := False;
 
 
@@ -1411,12 +1729,17 @@ begin
 
 
   if Result then
   if Result then
     begin
     begin
+{$IFDEF ARRAYBUF}
+//    bm.BookmarkData := CurrLinkItem;
+{$ELSE}
     bm.BookmarkData := CurrLinkItem;
     bm.BookmarkData := CurrLinkItem;
+{$ENDIF}
     bm.BookmarkFlag := bfCurrent;
     bm.BookmarkFlag := bfCurrent;
     GotoBookmark(@bm);
     GotoBookmark(@bm);
     end;
     end;
 
 
   ReAllocmem(ValueBuffer,0);
   ReAllocmem(ValueBuffer,0);
+{$ENDIF}
 end;
 end;
 
 
 begin
 begin

+ 1 - 0
packages/fcl-db/src/base/dbconst.pas

@@ -46,6 +46,7 @@ Resourcestring
   SInactiveDataset         = 'Operation cannot be performed on an inactive dataset';
   SInactiveDataset         = 'Operation cannot be performed on an inactive dataset';
   SInvalidDisplayValues    = '"%s" are not valid boolean displayvalues';
   SInvalidDisplayValues    = '"%s" are not valid boolean displayvalues';
   SInvalidFieldKind        = '%s : invalid field kind : ';
   SInvalidFieldKind        = '%s : invalid field kind : ';
+  SInvalidBookmark         = 'Invalid bookmark';
   SInvalidFieldSize        = 'Invalid field size : %d';
   SInvalidFieldSize        = 'Invalid field size : %d';
   SInvalidTypeConversion   = 'Invalid type conversion to %s in field %s';
   SInvalidTypeConversion   = 'Invalid type conversion to %s in field %s';
   SNeedField               = 'Field %s is required, but not supplied.';
   SNeedField               = 'Field %s is required, but not supplied.';