Browse Source

* Implemented some kind of AddIndex when ArrayBuf is defined

git-svn-id: trunk@9501 -
joost 17 years ago
parent
commit
5c1ce50a91
2 changed files with 277 additions and 98 deletions
  1. 276 98
      packages/fcl-db/src/base/bufdataset.pas
  2. 1 0
      packages/fcl-db/src/base/dbconst.pas

+ 276 - 98
packages/fcl-db/src/base/bufdataset.pas

@@ -106,13 +106,21 @@ type
 
 
   TRecordsUpdateBuffer = array of TRecUpdateBuffer;
   TRecordsUpdateBuffer = array of TRecUpdateBuffer;
 
 
-  TBufDataset = class(TDBDataSet)
-  private
+  TBufIndex = record
+    Name            : String;
+    SortField       : TField;
+    SortFieldName   : String;
 {$IFDEF ARRAYBUF}
 {$IFDEF ARRAYBUF}
     FCurrentRecInd  : integer;
     FCurrentRecInd  : integer;
     FRecordArray    : array of Pointer;
     FRecordArray    : array of Pointer;
     FLastRecInd     : integer;
     FLastRecInd     : integer;
-    
+{$ENDIF ARRAYBUF}
+  end;
+
+  TBufDataset = class(TDBDataSet)
+  private
+    FIndexes        : array of TBufIndex;
+{$IFDEF ARRAYBUF}
     FInitialBuffers : integer;
     FInitialBuffers : integer;
     FGrowBuffer     : integer;
     FGrowBuffer     : integer;
 {$ELSE}
 {$ELSE}
@@ -147,11 +155,15 @@ type
     FBlobBuffers      : array of PBlobBuffer;
     FBlobBuffers      : array of PBlobBuffer;
     FUpdateBlobBuffers: array of PBlobBuffer;
     FUpdateBlobBuffers: array of PBlobBuffer;
 
 
+    procedure AddRecordToIndex(var AIndex: TBufIndex; ARecBuf: pchar);
     function  GetCurrentBuffer: PChar;
     function  GetCurrentBuffer: PChar;
     procedure CalcRecordSize;
     procedure CalcRecordSize;
+    function GetIndexName: String;
+    procedure InitialiseIndex(AIndex: TBufIndex);
     function LoadBuffer(Buffer : PChar): TGetResult;
     function LoadBuffer(Buffer : PChar): TGetResult;
     function GetFieldSize(FieldDef : TFieldDef) : longint;
     function GetFieldSize(FieldDef : TFieldDef) : longint;
     function GetRecordUpdateBuffer : boolean;
     function GetRecordUpdateBuffer : boolean;
+    procedure SetIndexName(const AValue: String);
     procedure SetPacketRecords(aValue : integer);
     procedure SetPacketRecords(aValue : integer);
     function  IntAllocRecordBuffer: PChar;
     function  IntAllocRecordBuffer: PChar;
     procedure DoFilterRecord(var Acceptable: Boolean);
     procedure DoFilterRecord(var Acceptable: Boolean);
@@ -175,6 +187,7 @@ type
     procedure InternalClose; override;
     procedure InternalClose; override;
     function getnextpacket : integer;
     function getnextpacket : integer;
     function GetRecordSize: Word; override;
     function GetRecordSize: Word; override;
+    procedure InternalAddIndex(const AName, AFields : string); virtual;
     procedure InternalPost; override;
     procedure InternalPost; override;
     procedure InternalCancel; Override;
     procedure InternalCancel; Override;
     procedure InternalDelete; override;
     procedure InternalDelete; override;
@@ -214,16 +227,43 @@ type
     function Locate(const keyfields: string; const keyvalues: Variant; options: TLocateOptions) : boolean; override;
     function Locate(const keyfields: string; const keyvalues: Variant; options: TLocateOptions) : boolean; override;
     function UpdateStatus: TUpdateStatus; override;
     function UpdateStatus: TUpdateStatus; override;
     function CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream; override;
     function CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream; override;
+    procedure AddIndex(const AName, AFields : string); virtual;
     property ChangeCount : Integer read GetChangeCount;
     property ChangeCount : Integer read GetChangeCount;
   published
   published
     property PacketRecords : Integer read FPacketRecords write SetPacketRecords default 10;
     property PacketRecords : Integer read FPacketRecords write SetPacketRecords default 10;
     property OnUpdateError: TResolverErrorEvent read FOnUpdateError write SetOnUpdateError;
     property OnUpdateError: TResolverErrorEvent read FOnUpdateError write SetOnUpdateError;
+    property IndexName : String read GetIndexName write SetIndexName;
   end;
   end;
 
 
 implementation
 implementation
 
 
 uses variants, dbconst;
 uses variants, dbconst;
 
 
+function CompareText0(substr, astr: pchar; len : integer; options: TLocateOptions): integer;
+
+var
+  i : integer; Chr1, Chr2: byte;
+begin
+  result := 0;
+  i := 0;
+  chr1 := 1;
+  while (result=0) and (i<len) and (chr1 <> 0) do
+    begin
+    Chr1 := byte(substr[i]);
+    Chr2 := byte(astr[i]);
+    inc(i);
+    if loCaseInsensitive in options then
+      begin
+      if Chr1 in [97..122] then
+        dec(Chr1,32);
+      if Chr2 in [97..122] then
+        dec(Chr2,32);
+      end;
+    result := Chr1 - Chr2;
+    end;
+  if (result <> 0) and (chr1 = 0) and (loPartialKey in options) then result := 0;
+end;
+
 { ---------------------------------------------------------------------
 { ---------------------------------------------------------------------
     TBufDataSet
     TBufDataSet
   ---------------------------------------------------------------------}
   ---------------------------------------------------------------------}
@@ -232,14 +272,12 @@ constructor TBufDataset.Create(AOwner : TComponent);
 begin
 begin
   Inherited Create(AOwner);
   Inherited Create(AOwner);
 {$IFDEF ARRAYBUF}
 {$IFDEF ARRAYBUF}
-  FRecordArray:=nil;
-  FCurrentRecInd:=-1;
-  FLastRecInd:=-1;
-
   FInitialBuffers:=10000;
   FInitialBuffers:=10000;
   FGrowBuffer:=1000;
   FGrowBuffer:=1000;
-  
-  setlength(FRecordArray,FInitialBuffers);
+
+  FIndexesCount:=0;
+  InternalAddIndex('DEFAULT_ORDER','');
+  FCurrentIndex:=0;
 {$ELSE}
 {$ELSE}
 
 
   FIndexesCount:=2;
   FIndexesCount:=2;
@@ -298,6 +336,8 @@ end;
 
 
 procedure TBufDataset.InternalOpen;
 procedure TBufDataset.InternalOpen;
 
 
+var IndexNr : integer;
+
 begin
 begin
   CalcRecordSize;
   CalcRecordSize;
 
 
@@ -308,9 +348,12 @@ begin
   FLastRecBuf := FFirstRecBuf;
   FLastRecBuf := FFirstRecBuf;
   FCurrentRecBuf := FLastRecBuf;
   FCurrentRecBuf := FLastRecBuf;
 {$ELSE}
 {$ELSE}
-  FLastRecInd := 0;
-  FCurrentRecInd := 0;
-  FRecordArray[0]:=IntAllocRecordBuffer;
+  for IndexNr:=0 to FIndexesCount-1 do
+    begin
+    FIndexes[IndexNr].FLastRecInd := 0;
+    FIndexes[IndexNr].FCurrentRecInd := 0;
+    FIndexes[IndexNr].FRecordArray[0] := IntAllocRecordBuffer;
+    end;
 {$ENDIF}
 {$ENDIF}
 
 
   FAllPacketsFetched := False;
   FAllPacketsFetched := False;
@@ -335,9 +378,9 @@ var pc : pchar;
 begin
 begin
   FOpen:=False;
   FOpen:=False;
 {$IFDEF ARRAYBUF}
 {$IFDEF ARRAYBUF}
-  for r := 0 to FLastRecInd do
-    FreeRecordBuffer(FRecordArray[r]);
-  SetLength(FRecordArray,FInitialBuffers);
+  for r := 0 to FIndexes[FCurrentIndex].FLastRecInd do
+    FreeRecordBuffer(FIndexes[FCurrentIndex].FRecordArray[r]);
+  SetLength(FIndexes[FCurrentIndex].FRecordArray,FInitialBuffers);
 {$ELSE}
 {$ELSE}
   FCurrentRecBuf := FFirstRecBuf;
   FCurrentRecBuf := FFirstRecBuf;
   while assigned(FCurrentRecBuf) do
   while assigned(FCurrentRecBuf) do
@@ -383,8 +426,9 @@ 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}
 {$IFDEF ARRAYBUF}
-  if FCurrentRecInd <> FLastRecInd then
-    FCurrentRecInd := -1;
+  with FIndexes[FCurrentIndex] do
+    if FCurrentRecInd <> FLastRecInd then
+      FCurrentRecInd := -1;
 {$ELSE}
 {$ELSE}
   if FCurrentRecBuf <> FLastRecBuf then
   if FCurrentRecBuf <> FLastRecBuf then
     FCurrentRecBuf := nil;
     FCurrentRecBuf := nil;
@@ -396,7 +440,7 @@ begin
   repeat
   repeat
   until (getnextpacket < FPacketRecords) or (FPacketRecords = -1);
   until (getnextpacket < FPacketRecords) or (FPacketRecords = -1);
 {$IFDEF ARRAYBUF}
 {$IFDEF ARRAYBUF}
-  if FLastRecInd <> 0 then
+  with FIndexes[FCurrentIndex] do if FLastRecInd <> 0 then
     FCurrentRecInd := FLastRecInd;
     FCurrentRecInd := FLastRecInd;
 {$ELSE}
 {$ELSE}
   if FLastRecBuf <> FFirstRecBuf then
   if FLastRecBuf <> FFirstRecBuf then
@@ -432,10 +476,10 @@ begin
   case GetMode of
   case GetMode of
     gmPrior :
     gmPrior :
 {$IFDEF ARRAYBUF}
 {$IFDEF ARRAYBUF}
-      if FCurrentRecInd=0 then
+      if FIndexes[FCurrentIndex].FCurrentRecInd=0 then
         Result := grBOF
         Result := grBOF
       else
       else
-        Dec(FCurrentRecInd);
+        Dec(FIndexes[FCurrentIndex].FCurrentRecInd);
 {$ELSE}
 {$ELSE}
       if not assigned(FCurrentRecBuf[FCurrentIndex].prior) then
       if not assigned(FCurrentRecBuf[FCurrentIndex].prior) then
         begin
         begin
@@ -448,7 +492,7 @@ begin
 {$ENDIF}
 {$ENDIF}
     gmCurrent :
     gmCurrent :
 {$IFDEF ARRAYBUF}
 {$IFDEF ARRAYBUF}
-      if FCurrentRecInd = FLastRecInd then
+      if FIndexes[FCurrentIndex].FCurrentRecInd = FIndexes[FCurrentIndex].FLastRecInd then
         Result := grError;
         Result := grError;
 {$ELSE}
 {$ELSE}
       if FCurrentRecBuf = FLastRecBuf then
       if FCurrentRecBuf = FLastRecBuf then
@@ -456,16 +500,16 @@ begin
 {$ENDIF}
 {$ENDIF}
     gmNext :
     gmNext :
 {$IFDEF ARRAYBUF}
 {$IFDEF ARRAYBUF}
-      if FCurrentRecInd = FLastRecInd then // Dataset is empty (just opened)
+      if FIndexes[FCurrentIndex].FCurrentRecInd = FIndexes[FCurrentIndex].FLastRecInd then // Dataset is empty (just opened)
         begin
         begin
         if getnextpacket = 0 then result := grEOF;
         if getnextpacket = 0 then result := grEOF;
         end
         end
-      else if FCurrentRecInd = -1 then FCurrentRecInd := 0
-      else if FCurrentRecInd = FLastRecInd-1 then
+      else if FIndexes[FCurrentIndex].FCurrentRecInd = -1 then FIndexes[FCurrentIndex].FCurrentRecInd := 0
+      else if FIndexes[FCurrentIndex].FCurrentRecInd = FIndexes[FCurrentIndex].FLastRecInd-1 then
         begin
         begin
         if getnextpacket > 0 then
         if getnextpacket > 0 then
           begin
           begin
-          inc(FCurrentRecInd);
+          inc(FIndexes[FCurrentIndex].FCurrentRecInd);
           end
           end
         else
         else
           begin
           begin
@@ -474,7 +518,7 @@ begin
         end
         end
       else
       else
         begin
         begin
-        inc(FCurrentRecInd);
+        inc(FIndexes[FCurrentIndex].FCurrentRecInd);
         end;
         end;
 {$ELSE}
 {$ELSE}
       if FCurrentRecBuf = FLastRecBuf then // Dataset is empty (just opened)
       if FCurrentRecBuf = FLastRecBuf then // Dataset is empty (just opened)
@@ -506,15 +550,16 @@ begin
     with PBufBookmark(Buffer + FRecordSize)^ do
     with PBufBookmark(Buffer + FRecordSize)^ do
       begin
       begin
 {$IFDEF ARRAYBUF}
 {$IFDEF ARRAYBUF}
-      BookmarkData := FCurrentRecInd;
-      BookMarkBuf := FRecordArray[FCurrentRecInd];
+      BookmarkData := FIndexes[FCurrentIndex].FCurrentRecInd;
+      BookMarkBuf := FIndexes[FCurrentIndex].FRecordArray[FIndexes[FCurrentIndex].FCurrentRecInd];
 {$ELSE}
 {$ELSE}
       BookmarkData := FCurrentRecBuf;
       BookmarkData := FCurrentRecBuf;
 {$ENDIF}
 {$ENDIF}
       BookmarkFlag := bfCurrent;
       BookmarkFlag := bfCurrent;
       end;
       end;
 {$IFDEF ARRAYBUF}
 {$IFDEF ARRAYBUF}
-    move((FRecordArray[FCurrentRecInd])^,buffer^,FRecordSize);
+    with FIndexes[FCurrentIndex] do
+      move((FRecordArray[FCurrentRecInd])^,buffer^,FRecordSize);
 {$ELSE}
 {$ELSE}
     move((pointer(FCurrentRecBuf)+sizeof(TBufRecLinkItem)*FIndexesCount)^,buffer^,FRecordSize);
     move((pointer(FCurrentRecBuf)+sizeof(TBufRecLinkItem)*FIndexesCount)^,buffer^,FRecordSize);
 {$ENDIF}
 {$ENDIF}
@@ -577,10 +622,22 @@ begin
   Result := (FCurrentUpdateBuffer < length(FUpdateBuffer))  and CompareBuf(FCurrentUpdateBuffer);
   Result := (FCurrentUpdateBuffer < length(FUpdateBuffer))  and CompareBuf(FCurrentUpdateBuffer);
 end;
 end;
 
 
+procedure TBufDataset.SetIndexName(const AValue: String);
+var i : integer;
+begin
+  for i := 0 to FIndexesCount-1 do
+    if SameText(FIndexes[i].Name,AValue) then
+      begin
+      FCurrentIndex:=i;
+      Resync([rmCenter]);
+      exit;
+      end;
+end;
+
 procedure TBufDataset.InternalSetToRecord(Buffer: PChar);
 procedure TBufDataset.InternalSetToRecord(Buffer: PChar);
 begin
 begin
 {$IFDEF ARRAYBUF}
 {$IFDEF ARRAYBUF}
-  FCurrentRecInd:=GetRecordFromBookmark(PBufBookmark(Buffer + FRecordSize)^);
+  FIndexes[FCurrentIndex].FCurrentRecInd:=GetRecordFromBookmark(PBufBookmark(Buffer + FRecordSize)^);
 {$ELSE}
 {$ELSE}
   FCurrentRecBuf := PBufBookmark(Buffer + FRecordSize)^.BookmarkData;
   FCurrentRecBuf := PBufBookmark(Buffer + FRecordSize)^.BookmarkData;
 {$ENDIF}
 {$ENDIF}
@@ -619,16 +676,70 @@ 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}
 {$IFDEF ARRAYBUF}
-  FCurrentRecInd:=GetRecordFromBookmark(PBufBookmark(ABookmark)^);
+  FIndexes[FCurrentIndex].FCurrentRecInd:=GetRecordFromBookmark(PBufBookmark(ABookmark)^);
 {$ELSE}
 {$ELSE}
   FCurrentRecBuf := pointer(ABookmark^);
   FCurrentRecBuf := pointer(ABookmark^);
 {$ENDIF}
 {$ENDIF}
 end;
 end;
 
 
+procedure TBufDataset.AddRecordToIndex(var AIndex: TBufIndex; ARecBuf : pchar);
+{$IFDEF ARRAYBUF}
+var RecInd : integer;
+    NewValueBuf, CompValueBuf : pchar;
+    HighVal,LowVal : Integer;
+    cp : integer;
+{$ENDIF}
+begin
+{$IFDEF ARRAYBUF}
+  if not assigned(AIndex.SortField) then
+    AIndex.SortField := FieldByName(AIndex.SortFieldName);
+
+  NewValueBuf:=ARecBuf;
+  inc(NewValueBuf,FFieldBufPositions[AIndex.SortField.FieldNo-1]);
+  
+  HighVal := AIndex.FLastRecInd;
+  LowVal := 0;
+
+  repeat
+  RecInd := lowval+((HighVal-LowVal) div 2);
+  CompValueBuf:=AIndex.FRecordArray[RecInd]+FFieldBufPositions[AIndex.SortField.FieldNo-1];
+  if AIndex.SortField.DataType = ftString then
+    begin
+    cp := CompareText0(NewValueBuf,CompValueBuf,length(NewValueBuf),[]);
+    if cp >0 then
+      LowVal := RecInd
+    else
+      HighVal := RecInd;
+    end;
+  until abs(HighVal-LowVal)<2;
+  if cp <0 then RecInd:=RecInd else RecInd := RecInd+1;
+  if recind > AIndex.FLastRecInd then recind := AIndex.FLastRecInd;
+{
+  Write('New: ' + NewValueBuf);
+  Write(' Verg: ' + CompValueBuf);
+  CompValueBuf:=AIndex.FRecordArray[LowVal]+FFieldBufPositions[AIndex.SortField.FieldNo-1];
+  Write(' Low: ' + CompValueBuf + '('+inttostr(LowVal)+')');
+  CompValueBuf:=AIndex.FRecordArray[HighVal]+FFieldBufPositions[AIndex.SortField.FieldNo-1];
+  Write(' High: ' + CompValueBuf + '('+inttostr(HighVal)+')');
+  CompValueBuf:=AIndex.FRecordArray[RecInd]+FFieldBufPositions[AIndex.SortField.FieldNo-1];
+  Write(' RecIND: ' + CompValueBuf + '('+inttostr(RecInd)+')');
+  Writeln(' cp: ' + inttostr(cp));
+}
+
+  if (AIndex.FLastRecInd+1) >= length(AIndex.FRecordArray) then
+    SetLength(AIndex.FRecordArray,length(AIndex.FRecordArray)+FGrowBuffer);
+
+  move(AIndex.FRecordArray[RecInd],AIndex.FRecordArray[RecInd+1],sizeof(pointer)*(AIndex.FLastRecInd-RecInd+5)); // Let op. Moet zijn +1?
+  AIndex.FRecordArray[RecInd]:= ARecBuf;
+  inc(AIndex.FLastRecInd)
+{$ENDIF}
+end;
+
 function TBufDataset.getnextpacket : integer;
 function TBufDataset.getnextpacket : integer;
 
 
 var i : integer;
 var i : integer;
     pb : pchar;
     pb : pchar;
+    IndexNr : integer;
     
     
 begin
 begin
   if FAllPacketsFetched then
   if FAllPacketsFetched then
@@ -638,18 +749,26 @@ begin
     end;
     end;
   i := 0;
   i := 0;
 {$IFDEF ARRAYBUF}
 {$IFDEF ARRAYBUF}
-  pb := pchar(FRecordArray[FLastRecInd]);
+  with FIndexes[FCurrentIndex] do
+    pb := pchar(FRecordArray[FLastRecInd]);
 {$ELSE}
 {$ELSE}
   pb := pchar(pointer(FLastRecBuf)+sizeof(TBufRecLinkItem)*FIndexesCount);
   pb := pchar(pointer(FLastRecBuf)+sizeof(TBufRecLinkItem)*FIndexesCount);
 {$ENDIF}
 {$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}
 {$IFDEF ARRAYBUF}
-    inc(FLastRecInd);
-    if FLastRecInd >= length(FRecordArray) then
-      SetLength(FRecordArray,length(FRecordArray)+FGrowBuffer);
-    FRecordArray[FLastRecInd]:=IntAllocRecordBuffer;
-    pb := pchar(FRecordArray[FLastRecInd]);
+    with FIndexes[0] do
+      begin
+      inc(FLastRecInd);
+      if FLastRecInd >= length(FRecordArray) then
+        SetLength(FRecordArray,length(FRecordArray)+FGrowBuffer);
+      FRecordArray[FLastRecInd]:=IntAllocRecordBuffer;
+      end;
+
+    for IndexNr:= 1 to FIndexesCount-1 do
+      AddRecordToIndex(FIndexes[IndexNr],pb);
+
+    pb := pchar(FIndexes[FCurrentIndex].FRecordArray[FIndexes[FCurrentIndex].FLastRecInd]);
 {$ELSE}
 {$ELSE}
     FLastRecBuf^.next := pointer(IntAllocRecordBuffer);
     FLastRecBuf^.next := pointer(IntAllocRecordBuffer);
     FLastRecBuf^.next^.prior := FLastRecBuf;
     FLastRecBuf^.next^.prior := FLastRecBuf;
@@ -815,7 +934,8 @@ begin
     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}
 {$IFDEF ARRAYBUF}
-    CurrBuff := FRecordArray[FLastRecInd]
+    with FIndexes[FCurrentIndex] do
+      CurrBuff := FRecordArray[FLastRecInd]
 {$ELSE}
 {$ELSE}
     CurrBuff := pointer(FLastRecBuf) + sizeof(TBufRecLinkItem)*FIndexesCount
     CurrBuff := pointer(FLastRecBuf) + sizeof(TBufRecLinkItem)*FIndexesCount
 {$ENDIF}
 {$ENDIF}
@@ -865,9 +985,12 @@ begin
     SetLength(FUpdateBuffer,FCurrentUpdateBuffer+1);
     SetLength(FUpdateBuffer,FCurrentUpdateBuffer+1);
 
 
 {$IFDEF ARRAYBUF}
 {$IFDEF ARRAYBUF}
-    FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer := FRecordArray[FCurrentRecInd];
-    FUpdateBuffer[FCurrentUpdateBuffer].Bookmark.BookMarkBuf:=nil;
-    FUpdateBuffer[FCurrentUpdateBuffer].Bookmark.BookmarkData := FCurrentRecInd;
+    with FIndexes[FCurrentIndex] do
+      begin
+      FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer := FRecordArray[FCurrentRecInd];
+      FUpdateBuffer[FCurrentUpdateBuffer].Bookmark.BookMarkBuf:=nil;
+      FUpdateBuffer[FCurrentUpdateBuffer].Bookmark.BookmarkData := FCurrentRecInd;
+      end;
 {$ELSE}
 {$ELSE}
     FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer := pchar(FCurrentRecBuf);
     FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer := pchar(FCurrentRecBuf);
     FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData := FCurrentRecBuf;
     FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData := FCurrentRecBuf;
@@ -880,9 +1003,12 @@ begin
     if FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind = ukModify then
     if FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind = ukModify then
       begin
       begin
 {$IFDEF ARRAYBUF}
 {$IFDEF ARRAYBUF}
-      FreeRecordBuffer(FRecordArray[FCurrentRecInd]);
-      FUpdateBuffer[FCurrentUpdateBuffer].Bookmark.BookmarkData := FCurrentRecInd;
-      FUpdateBuffer[FCurrentUpdateBuffer].Bookmark.BookMarkBuf := nil;
+      with FIndexes[FCurrentIndex] do
+        begin
+        FreeRecordBuffer(FRecordArray[FCurrentRecInd]);
+        FUpdateBuffer[FCurrentUpdateBuffer].Bookmark.BookmarkData := FCurrentRecInd;
+        FUpdateBuffer[FCurrentUpdateBuffer].Bookmark.BookMarkBuf := nil;
+        end;
 {$ELSE}
 {$ELSE}
       FCurrentRecBuf := FCurrentRecBuf^.next;
       FCurrentRecBuf := FCurrentRecBuf^.next;
       FreeRecordBuffer(pchar(FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData));
       FreeRecordBuffer(pchar(FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData));
@@ -892,7 +1018,7 @@ begin
     else
     else
       begin
       begin
 {$IFDEF ARRAYBUF}
 {$IFDEF ARRAYBUF}
-      FreeRecordBuffer(pchar(FRecordArray[GetRecordFromBookmark(FUpdateBuffer[FCurrentUpdateBuffer].Bookmark)]));
+      FreeRecordBuffer(pchar(FIndexes[FCurrentIndex].FRecordArray[GetRecordFromBookmark(FUpdateBuffer[FCurrentUpdateBuffer].Bookmark)]));
       FUpdateBuffer[FCurrentUpdateBuffer].Bookmark.BookmarkData := -1;  //this 'disables' the updatebuffer
       FUpdateBuffer[FCurrentUpdateBuffer].Bookmark.BookmarkData := -1;  //this 'disables' the updatebuffer
 {$ELSE}
 {$ELSE}
       FCurrentRecBuf := FCurrentRecBuf^.next;
       FCurrentRecBuf := FCurrentRecBuf^.next;
@@ -903,8 +1029,11 @@ begin
     end;
     end;
 
 
 {$IFDEF ARRAYBUF}
 {$IFDEF ARRAYBUF}
-  Move(FRecordArray[FCurrentRecInd+1],FRecordArray[FCurrentRecInd],sizeof(Pointer)*(FLastRecInd-FCurrentRecInd));
-  dec(FLastRecInd);
+  with FIndexes[FCurrentIndex] do
+    begin
+    Move(FRecordArray[FCurrentRecInd+1],FRecordArray[FCurrentRecInd],sizeof(Pointer)*(FLastRecInd-FCurrentRecInd));
+    dec(FLastRecInd);
+    end;
 {$ENDIF}
 {$ENDIF}
 
 
   dec(FBRecordCount);
   dec(FBRecordCount);
@@ -942,8 +1071,11 @@ begin
         if UpdateKind = ukModify then
         if UpdateKind = ukModify then
           begin
           begin
 {$IFDEF ARRAYBUF}
 {$IFDEF ARRAYBUF}
-          FreeRecordBuffer(FRecordArray[Bookmark.BookmarkData]);
-          FRecordArray[Bookmark.BookmarkData] := OldValuesBuffer;
+          with FIndexes[FCurrentIndex] do
+            begin
+            FreeRecordBuffer(FRecordArray[Bookmark.BookmarkData]);
+            FRecordArray[Bookmark.BookmarkData] := OldValuesBuffer;
+            end;
 {$ELSE}
 {$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);
@@ -953,9 +1085,12 @@ begin
           begin
           begin
 {$IFDEF ARRAYBUF}
 {$IFDEF ARRAYBUF}
           RecInd := GetRecordFromBookmark(Bookmark);
           RecInd := GetRecordFromBookmark(Bookmark);
-          move(FRecordArray[RecInd],FRecordArray[RecInd+1],sizeof(Pointer)*(FLastRecInd-RecInd+1));
-          FRecordArray[RecInd] := OldValuesBuffer;
-          inc(FLastRecInd);
+          with FIndexes[FCurrentIndex] do
+            begin
+            move(FRecordArray[RecInd],FRecordArray[RecInd+1],sizeof(Pointer)*(FLastRecInd-RecInd+1));
+            FRecordArray[RecInd] := OldValuesBuffer;
+            inc(FLastRecInd);
+            end;
 {$ELSE}
 {$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
@@ -969,9 +1104,9 @@ begin
           begin
           begin
 {$IFDEF ARRAYBUF}
 {$IFDEF ARRAYBUF}
           RecInd := GetRecordFromBookmark(Bookmark);
           RecInd := GetRecordFromBookmark(Bookmark);
-          FreeRecordBuffer(FRecordArray[RecInd]);
-          move(FRecordArray[RecInd+1],FRecordArray[RecInd],sizeof(Pointer)*(FLastRecInd-RecInd));
-          dec(FLastRecInd);
+          FreeRecordBuffer(FIndexes[FCurrentIndex].FRecordArray[RecInd]);
+          move(FIndexes[FCurrentIndex].FRecordArray[RecInd+1],FIndexes[FCurrentIndex].FRecordArray[RecInd],sizeof(Pointer)*(FIndexes[FCurrentIndex].FLastRecInd-RecInd));
+          dec(FIndexes[FCurrentIndex].FLastRecInd);
 {$ELSE}
 {$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
@@ -1137,7 +1272,8 @@ begin
     if GetBookmarkFlag(ActiveBuffer) = bfEOF then
     if GetBookmarkFlag(ActiveBuffer) = bfEOF then
       // Append
       // Append
 {$IFDEF ARRAYBUF}
 {$IFDEF ARRAYBUF}
-      FCurrentRecInd := FLastRecInd
+      with FIndexes[FCurrentIndex] do
+        FCurrentRecInd := FLastRecInd
 {$ELSE}
 {$ELSE}
       FCurrentRecBuf := FLastRecBuf
       FCurrentRecBuf := FLastRecBuf
 {$ENDIF}
 {$ENDIF}
@@ -1148,11 +1284,14 @@ begin
       InternalSetToRecord(ActiveBuffer);
       InternalSetToRecord(ActiveBuffer);
 
 
 {$IFDEF ARRAYBUF}
 {$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);
+    with FIndexes[FCurrentIndex] do
+      begin
+      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);
+      end;
 {$ELSE}
 {$ELSE}
     // Create the new record buffer
     // Create the new record buffer
     tmpRecBuffer := FCurrentRecBuf^.prior;
     tmpRecBuffer := FCurrentRecBuf^.prior;
@@ -1173,7 +1312,7 @@ begin
     with PBufBookmark(ActiveBuffer + FRecordSize)^ do
     with PBufBookmark(ActiveBuffer + FRecordSize)^ do
       begin
       begin
 {$IFDEF ARRAYBUF}
 {$IFDEF ARRAYBUF}
-      BookmarkData := FCurrentRecInd;
+      BookmarkData := FIndexes[FCurrentIndex].FCurrentRecInd;
 {$ELSE}
 {$ELSE}
       BookmarkData := FCurrentRecBuf;
       BookmarkData := FCurrentRecBuf;
 {$ENDIF}
 {$ENDIF}
@@ -1191,8 +1330,11 @@ begin
     SetLength(FUpdateBuffer,FCurrentUpdateBuffer+1);
     SetLength(FUpdateBuffer,FCurrentUpdateBuffer+1);
 
 
 {$IFDEF ARRAYBUF}
 {$IFDEF ARRAYBUF}
-    FUpdateBuffer[FCurrentUpdateBuffer].Bookmark.BookmarkData := FCurrentRecInd;
-    FUpdateBuffer[FCurrentUpdateBuffer].Bookmark.BookMarkBuf := FRecordArray[FCurrentRecInd];
+    with FIndexes[FCurrentIndex] do
+      begin
+      FUpdateBuffer[FCurrentUpdateBuffer].Bookmark.BookmarkData := FCurrentRecInd;
+      FUpdateBuffer[FCurrentUpdateBuffer].Bookmark.BookMarkBuf := FRecordArray[FCurrentRecInd];
+      end;
 {$ELSE}
 {$ELSE}
     FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData := FCurrentRecBuf;
     FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData := FCurrentRecBuf;
 {$ENDIF}
 {$ENDIF}
@@ -1202,7 +1344,8 @@ begin
       // Update the oldvalues-buffer
       // Update the oldvalues-buffer
       FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer := intAllocRecordBuffer;
       FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer := intAllocRecordBuffer;
 {$IFDEF ARRAYBUF}
 {$IFDEF ARRAYBUF}
-      move(FRecordArray[FCurrentRecInd]^,FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer^,FRecordSize);
+      with FIndexes[FCurrentIndex] do
+        move(FRecordArray[FCurrentRecInd]^,FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer^,FRecordSize);
 {$ELSE}
 {$ELSE}
       move(FCurrentRecBuf^,FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer^,FRecordSize+sizeof(TBufRecLinkItem)*FIndexesCount);
       move(FCurrentRecBuf^,FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer^,FRecordSize+sizeof(TBufRecLinkItem)*FIndexesCount);
 {$ENDIF}
 {$ENDIF}
@@ -1213,7 +1356,8 @@ begin
     end;
     end;
 
 
 {$IFDEF ARRAYBUF}
 {$IFDEF ARRAYBUF}
-  move(ActiveBuffer^,FRecordArray[FCurrentRecInd]^,FRecordSize);
+  with FIndexes[FCurrentIndex] do
+    move(ActiveBuffer^,FRecordArray[FCurrentRecInd]^,FRecordSize);
 {$ELSE}
 {$ELSE}
   CurrBuff := pchar(FCurrentRecBuf);
   CurrBuff := pchar(FCurrentRecBuf);
   inc(Currbuff,sizeof(TBufRecLinkItem)*FIndexesCount);
   inc(Currbuff,sizeof(TBufRecLinkItem)*FIndexesCount);
@@ -1236,6 +1380,13 @@ begin
     end;
     end;
 end;
 end;
 
 
+function TBufDataset.GetIndexName: String;
+begin
+{$IFDEF ARRAYBUF}
+  result := FIndexes[FCurrentIndex].Name;
+{$ENDIF}
+end;
+
 function TBufDataset.GetRecordSize : Word;
 function TBufDataset.GetRecordSize : Word;
 
 
 begin
 begin
@@ -1478,6 +1629,27 @@ begin
     end;
     end;
 end;
 end;
 
 
+procedure TBufDataset.AddIndex(const AName, AFields: string);
+begin
+  if AFields='' then DatabaseError(SNoIndexFieldNameGiven);
+  InternalAddIndex(AName,AFields);
+  // If not all packets are fetched, you can not sort properly.
+  FPacketRecords:=-1;
+end;
+
+procedure TBufDataset.InternalAddIndex(const AName, AFields: string);
+begin
+{$IFDEF ARRAYBUF}
+  inc(FIndexesCount);
+  setlength(FIndexes,FIndexesCount);
+  InitialiseIndex(FIndexes[FIndexesCount-1]);
+  FIndexes[FIndexesCount-1].Name:=AName;
+  FIndexes[FIndexesCount-1].SortFieldName:=AFields;
+  if Active then FIndexes[FIndexesCount-1].SortField := FieldByName(AFields);
+  setlength(FIndexes[FIndexesCount-1].FRecordArray,FInitialBuffers);
+{$ENDIF}
+end;
+
 procedure TBufDataset.DoFilterRecord(var Acceptable: Boolean);
 procedure TBufDataset.DoFilterRecord(var Acceptable: Boolean);
 begin
 begin
   Acceptable := true;
   Acceptable := true;
@@ -1521,8 +1693,13 @@ end;
 
 
 procedure TBufDataset.AddSecondIndex;
 procedure TBufDataset.AddSecondIndex;
 
 
-var ALinkItem,
+var
+{$IFNDEF ARRAYBUF}
+    ALinkItem,
     ANewLinkItem : PBufRecLinkItem;
     ANewLinkItem : PBufRecLinkItem;
+{$ELSE}
+    aRecNo : Integer;
+{$ENDIF}
 
 
 begin
 begin
 {$IFNDEF ARRAYBUF}
 {$IFNDEF ARRAYBUF}
@@ -1551,7 +1728,35 @@ begin
   FFirstRecBuf:=FFirstRecBufs[FCurrentIndex];
   FFirstRecBuf:=FFirstRecBufs[FCurrentIndex];
   FCurrentRecBuf:=FFirstRecBuf;
   FCurrentRecBuf:=FFirstRecBuf;
 
 
+{$ELSE}
+// Maak index
+  inc(FIndexesCount);
+  setlength(FIndexes,FIndexesCount);
+  InitialiseIndex(FIndexes[FIndexesCount-1]);
+
+// Stel index in
+  inc(FCurrentIndex);
+
+// Vul index - reverse van index 0
+  SetLength(FIndexes[FCurrentIndex].FRecordArray,length(FIndexes[0].FRecordArray));
+  FIndexes[FCurrentIndex].FCurrentRecInd:=0;
+  FIndexes[FCurrentIndex].FLastRecInd:=FIndexes[0].FLastRecInd;
+  for arecno := 0 to FIndexes[FCurrentIndex].FLastRecInd-1 do
+    begin
+    FIndexes[FCurrentIndex].FRecordArray[aRecNo] := FIndexes[0].FRecordArray[FIndexes[0].FLastRecInd-aRecNo-1];
+//    FIndexes[FCurrentIndex].FRecordArray[aRecNo] := FIndexes[0].FRecordArray[aRecNo];
+    end;
+  FIndexes[FCurrentIndex].FRecordArray[FIndexes[FCurrentIndex].FLastRecInd] := FIndexes[0].FRecordArray[FIndexes[0].FLastRecInd];
+{$ENDIF}
   Resync([rmExact,rmCenter]);
   Resync([rmExact,rmCenter]);
+end;
+
+procedure TBufDataset.InitialiseIndex(AIndex : TBufIndex);
+begin
+{$IFDEF ARRAYBUF}
+  AIndex.FRecordArray:=nil;
+  AIndex.FCurrentRecInd:=-1;
+  AIndex.FLastRecInd:=-1;
 {$ENDIF}
 {$ENDIF}
 end;
 end;
 
 
@@ -1581,23 +1786,23 @@ end;
 function TBufDataset.GetRecordFromBookmark(ABookMark: TBufBookmark) : integer;
 function TBufDataset.GetRecordFromBookmark(ABookMark: TBufBookmark) : integer;
 begin
 begin
   // ABookmark.BookMarkBuf is nil if SetRecNo calls GotoBookmark
   // ABookmark.BookMarkBuf is nil if SetRecNo calls GotoBookmark
-  if (ABookmark.BookMarkBuf<>nil) and (FRecordArray[ABookmark.BookmarkData]<>ABookmark.BookMarkBuf) then
+  if (ABookmark.BookMarkBuf<>nil) and (FIndexes[FCurrentIndex].FRecordArray[ABookmark.BookmarkData]<>ABookmark.BookMarkBuf) then
     begin
     begin
     if ABookmark.BookmarkData > 2 then
     if ABookmark.BookmarkData > 2 then
       Result := ABookmark.BookmarkData-2
       Result := ABookmark.BookmarkData-2
     else
     else
       Result := 0;
       Result := 0;
 
 
-    while (Result<FLastRecInd) do
+    while (Result<FIndexes[FCurrentIndex].FLastRecInd) do
       begin
       begin
-      if (FRecordArray[Result] = ABookmark.BookMarkBuf) then exit;
+      if (FIndexes[FCurrentIndex].FRecordArray[Result] = ABookmark.BookMarkBuf) then exit;
       inc(Result);
       inc(Result);
       end;
       end;
 
 
     Result:=0;
     Result:=0;
     while (Result<ABookmark.BookmarkData) do
     while (Result<ABookmark.BookmarkData) do
       begin
       begin
-      if (FRecordArray[Result] = ABookmark.BookMarkBuf) then exit;
+      if (FIndexes[FCurrentIndex].FRecordArray[Result] = ABookmark.BookMarkBuf) then exit;
       inc(Result);
       inc(Result);
       end;
       end;
 
 
@@ -1610,33 +1815,6 @@ end;
 
 
 Function TBufDataset.Locate(const KeyFields: string; const KeyValues: Variant; options: TLocateOptions) : boolean;
 Function TBufDataset.Locate(const KeyFields: string; const KeyValues: Variant; options: TLocateOptions) : boolean;
 
 
-
-  function CompareText0(substr, astr: pchar; len : integer; options: TLocateOptions): integer;
-
-  var
-    i : integer; Chr1, Chr2: byte;
-  begin
-    result := 0;
-    i := 0;
-    chr1 := 1;
-    while (result=0) and (i<len) and (chr1 <> 0) do
-      begin
-      Chr1 := byte(substr[i]);
-      Chr2 := byte(astr[i]);
-      inc(i);
-      if loCaseInsensitive in options then
-        begin
-        if Chr1 in [97..122] then
-          dec(Chr1,32);
-        if Chr2 in [97..122] then
-          dec(Chr2,32);
-        end;
-      result := Chr1 - Chr2;
-      end;
-    if (result <> 0) and (chr1 = 0) and (loPartialKey in options) then result := 0;
-  end;
-
-
 var keyfield    : TField;     // Field to search in
 var keyfield    : TField;     // Field to search in
     ValueBuffer : pchar;      // Pointer to value to search for, in TField' internal format
     ValueBuffer : pchar;      // Pointer to value to search for, in TField' internal format
     VBLength    : integer;
     VBLength    : integer;

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

@@ -98,6 +98,7 @@ Resourcestring
   SNotIndexField           = 'Field ''%s'' is not indexed and cannot be modified';
   SNotIndexField           = 'Field ''%s'' is not indexed and cannot be modified';
   SErrUnknownConnectorType = 'Unknown connector type';
   SErrUnknownConnectorType = 'Unknown connector type';
   SErrAmountStrings        = 'Amount of search and replace strings don''t match';
   SErrAmountStrings        = 'Amount of search and replace strings don''t match';
+  SNoIndexFieldNameGiven   = 'There are no fields selected to base the index on';
   SErrCircularDataSourceReferenceNotAllowed = 'Circular datasource references are not allowed.';
   SErrCircularDataSourceReferenceNotAllowed = 'Circular datasource references are not allowed.';