Browse Source

fcl-db: bufdataset: when new record is inserted or existing edited and some sorted index is presented record is moved to proper position in index. (introduces OrderCurrentRecord method). Small drawback is than in case of inserting record new record is first inserted before current record and then moved to proper position.(but it takes only few memory operations in current implementation).
Bug #23465

git-svn-id: trunk@23592 -

lacak 12 years ago
parent
commit
1b9842c33a
2 changed files with 53 additions and 12 deletions
  1. 47 8
      packages/fcl-db/src/base/bufdataset.pas
  2. 6 4
      packages/fcl-db/tests/testdbbasics.pas

+ 47 - 8
packages/fcl-db/src/base/bufdataset.pas

@@ -161,14 +161,14 @@ type
     // Inserts a record before the current record, or if the record is sorted,
     // inserts it in the proper position
     procedure InsertRecordBeforeCurrentRecord(Const ARecord : TRecordBuffer); virtual; abstract;
+    procedure OrderCurrentRecord; virtual; abstract;
     procedure EndUpdate; virtual; abstract;
     
     procedure RemoveRecordFromIndex(const ABookmark : TBufBookmark); virtual; abstract;
-    
+
     function CompareBookmarks(const ABookmark1, ABookmark2 : PBufBookmark) : boolean; virtual;
     Function GetRecNo(const ABookmark : PBufBookmark) : integer; virtual; abstract;
 
-
     property SpareRecord : TRecordBuffer read GetSpareRecord;
     property SpareBuffer : TRecordBuffer read GetSpareBuffer;
     property CurrentRecord : TRecordBuffer read GetCurrentRecord;
@@ -228,6 +228,7 @@ type
     procedure BeginUpdate; override;
     procedure AddRecord; override;
     procedure InsertRecordBeforeCurrentRecord(Const ARecord : TRecordBuffer); override;
+    procedure OrderCurrentRecord; override;
     procedure EndUpdate; override;
   end;
 
@@ -273,6 +274,7 @@ type
     procedure BeginUpdate; override;
     procedure AddRecord; override;
     procedure InsertRecordBeforeCurrentRecord(Const ARecord : TRecordBuffer); override;
+    procedure OrderCurrentRecord; override;
     procedure EndUpdate; override;
   end;
 
@@ -1466,6 +1468,37 @@ begin
   ANewRecord[IndNr].next[IndNr].prior:=ANewRecord;
 end;
 
+procedure TDoubleLinkedBufIndex.OrderCurrentRecord;
+var ARecord: PBufRecLinkItem;
+    ABookmark: TBufBookmark;
+begin
+  // all records except current are already sorted
+  // check prior records
+  ARecord := FCurrentRecBuf;
+  repeat
+    ARecord := ARecord[IndNr].prior;
+  until not assigned(ARecord) or (IndexCompareRecords(ARecord, FCurrentRecBuf, DBCompareStruct) <= 0);
+  if assigned(ARecord) then
+    ARecord := ARecord[IndNr].next
+  else
+    ARecord := FFirstRecBuf;
+  if ARecord = FCurrentRecBuf then
+  begin
+    // prior record is less equal than current
+    // check next records
+    repeat
+      ARecord := ARecord[IndNr].next;
+    until (ARecord=FLastRecBuf) or (IndexCompareRecords(ARecord, FCurrentRecBuf, DBCompareStruct) >= 0);
+    if ARecord = FCurrentRecBuf[IndNr].next then
+      Exit; // current record is on proper position
+  end;
+  StoreCurrentRecIntoBookmark(@ABookmark);
+  RemoveRecordFromIndex(ABookmark);
+  FCurrentRecBuf := ARecord;
+  InsertRecordBeforeCurrentRecord(TRecordBuffer(ABookmark.BookmarkData));
+  GotoBookmark(@ABookmark);
+end;
+
 procedure TDoubleLinkedBufIndex.EndUpdate;
 begin
   FLastRecBuf[IndNr].next := FFirstRecBuf;
@@ -2242,18 +2275,14 @@ begin
       end;
 
     // Link the newly created record buffer to the newly created TDataset record
-    with ABookmark^ do
-      begin
-      FCurrentIndex.StoreCurrentRecIntoBookmark(@BookmarkData);
-      BookmarkFlag := bfInserted;
-      end;
+    FCurrentIndex.StoreCurrentRecIntoBookmark(ABookmark);
+    ABookmark^.BookmarkFlag := bfInserted;
 
     inc(FBRecordCount);
     end
   else
     InternalSetToRecord(ActiveBuffer);
 
-
   // If there is no updatebuffer already, add one
   if not GetActiveRecordUpdateBuffer then
     begin
@@ -2281,6 +2310,11 @@ begin
     end;
 
   move(ActiveBuffer^,FCurrentIndex.CurrentBuffer^,FRecordSize);
+
+  // new data are now in current record so reorder current record if needed
+  for i := 1 to FIndexesCount-1 do
+    if (i<>1) or (FIndexes[i]=FCurrentIndex) then
+      FIndexes[i].OrderCurrentRecord;
 end;
 
 procedure TCustomBufDataset.CalcRecordSize;
@@ -3683,6 +3717,11 @@ begin
   // Do nothing
 end;
 
+procedure TUniDirectionalBufIndex.OrderCurrentRecord;
+begin
+  // Do nothing
+end;
+
 procedure TUniDirectionalBufIndex.EndUpdate;
 begin
   // Do nothing

+ 6 - 4
packages/fcl-db/tests/testdbbasics.pas

@@ -2111,6 +2111,7 @@ procedure TTestBufDatasetDBBasics.TestIndexAppendRecord;
 var i: integer;
     LastValue: string;
 begin
+  // start with empty dataset
   with DBConnector.GetNDataset(true,0) as TCustomBufDataset do
   begin
     MaxIndexesCount:=4;
@@ -2125,19 +2126,20 @@ begin
     // append data at end
     for i:=20 downto 0 do
       AppendRecord([i, inttostr(i)]);
-    First;
     // insert data at begining
+    IndexName:='';
+    First;
     for i:=21 to 22 do
       InsertRecord([i, inttostr(i)]);
 
-    // ATM new records are not ordered as they are added ?
+    // swith to index and check if records are ordered
+    IndexName := 'testindex';
     LastValue := '';
     First;
     for i:=22 downto 0 do
     begin
       CheckEquals(23-i, RecNo, 'testindex.RecNo:');
-      CheckEquals(inttostr(i), Fields[1].AsString, 'testindex.Fields[1].Value:');
-      //CheckTrue(AnsiCompareStr(LastValue,Fields[1].AsString) < 0, 'testindex.LastValue>CurrValue');
+      CheckTrue(AnsiCompareStr(LastValue,Fields[1].AsString) < 0, 'testindex.LastValue>=CurrValue');
       LastValue := Fields[1].AsString;
       Next;
     end;