Browse Source

Fix from Lacak2 for Mantis #21994 fixes

* when records are inserted into empty dataset and then all canceled by CancelUpdates AV is raised
* another fix for bug #18004, applied in rev.20531 (improved in rev.21197)
  (original approach is not good because when record is inserted and deleted and again inserted,
   then same memory block can be returned, which leads to confusion, because we get same BookmarkData for distinct records)
* +test 

git-svn-id: trunk@21280 -
marco 13 years ago
parent
commit
642a180809

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

@@ -555,7 +555,7 @@ type
     Property AutoCalcFields;
     Property AutoCalcFields;
     Property Filter;
     Property Filter;
     Property Filtered;
     Property Filtered;
-    Property Readonly;
+    Property ReadOnly;
     Property AfterCancel;
     Property AfterCancel;
     Property AfterClose;
     Property AfterClose;
     Property AfterDelete;
     Property AfterDelete;
@@ -1195,6 +1195,8 @@ begin
       begin
       begin
       if assigned(OldValuesBuffer) then
       if assigned(OldValuesBuffer) then
         FreeRecordBuffer(OldValuesBuffer);
         FreeRecordBuffer(OldValuesBuffer);
+      if (UpdateKind = ukDelete) and assigned(BookmarkData.BookmarkData) then
+        FreeRecordBuffer(TRecordBuffer(BookmarkData.BookmarkData));
       end;
       end;
     end;
     end;
   SetLength(FUpdateBuffer,0);
   SetLength(FUpdateBuffer,0);
@@ -1930,7 +1932,7 @@ end;
 
 
 procedure TCustomBufDataset.InternalDelete;
 procedure TCustomBufDataset.InternalDelete;
 var i : Integer;
 var i : Integer;
-    RemRec, FreeRec : pointer;
+    RemRec : pointer;
     RemRecBookmrk : TBufBookmark;
     RemRecBookmrk : TBufBookmark;
 begin
 begin
   InternalSetToRecord(ActiveBuffer);
   InternalSetToRecord(ActiveBuffer);
@@ -1949,15 +1951,16 @@ begin
     FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer := IntAllocRecordBuffer;
     FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer := IntAllocRecordBuffer;
     move(RemRec^, FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer^,FRecordSize);
     move(RemRec^, FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer^,FRecordSize);
     end
     end
-  else //with FIndexes[0] do
+  else
     begin
     begin
     if FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind <> ukModify then
     if FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind <> ukModify then
       begin
       begin
       FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer := nil;  //this 'disables' the updatebuffer
       FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer := nil;  //this 'disables' the updatebuffer
-      FreeRec := RemRecBookmrk.BookmarkData;  // mantis #18004
-      FreeRecordBuffer(TRecordBuffer(FreeRec));
-      // RemRecBookmrk.BookmarkData still points to just freed record buffer
-      // There could be record in update-buffer, linked to this record
+      // Do NOT release record buffer (pointed by RemRecBookmrk.BookmarkData) here
+      //  - When record is inserted and deleted(and memory released) and again inserted then same memory block can be returned
+      //    which leads to confusion, because we get same BookmarkData for distinct records
+      //  - In CancelUpdates when records are restored it is expected, that deleted records still exists in memory
+      // There also could be record(s) in update-buffer, linked to this record.
       end;
       end;
     end;
     end;
   FCurrentIndex.StoreCurrentRecIntoBookmark(@FUpdateBuffer[FCurrentUpdateBuffer].NextBookmarkData);
   FCurrentIndex.StoreCurrentRecIntoBookmark(@FUpdateBuffer[FCurrentUpdateBuffer].NextBookmarkData);
@@ -2025,7 +2028,8 @@ var StoreRecBM     : TBufBookmark;
           begin
           begin
           GotoBookmark(@StoreRecBM);
           GotoBookmark(@StoreRecBM);
           if ScrollForward = grEOF then
           if ScrollForward = grEOF then
-            ScrollBackward;
+            if ScrollBackward = grBOF then
+              ScrollLast;  // last record will be removed from index, so move to spare record
           StoreCurrentRecIntoBookmark(@StoreRecBM);
           StoreCurrentRecIntoBookmark(@StoreRecBM);
           end;
           end;
         FCurrentIndex.RemoveRecordFromIndex(Bm);
         FCurrentIndex.RemoveRecordFromIndex(Bm);

+ 8 - 0
packages/fcl-db/tests/testbufdatasetstreams.pas

@@ -48,6 +48,7 @@ type
     procedure SeveralEditsCancelUpd;
     procedure SeveralEditsCancelUpd;
     procedure DeleteAllCancelUpd;
     procedure DeleteAllCancelUpd;
     procedure DeleteAllInsertCancelUpd;
     procedure DeleteAllInsertCancelUpd;
+    procedure AppendDeleteCancelUpd;
 
 
     procedure TestSimpleEditApplUpd;
     procedure TestSimpleEditApplUpd;
     procedure TestSimpleDeleteApplUpd;
     procedure TestSimpleDeleteApplUpd;
@@ -339,6 +340,7 @@ end;
 
 
 procedure TTestBufDatasetStreams.AppendDeleteChange(ADataset: TCustomBufDataset);
 procedure TTestBufDatasetStreams.AppendDeleteChange(ADataset: TCustomBufDataset);
 begin
 begin
+  // Tests bugs #19593, #21994
   with ADataset do
   with ADataset do
   begin
   begin
     AppendRecord([16,'TestName16']);
     AppendRecord([16,'TestName16']);
@@ -347,6 +349,7 @@ begin
     Prior;
     Prior;
     Delete;  // 15 update-buffer of deleted record is linked to 16
     Delete;  // 15 update-buffer of deleted record is linked to 16
     Delete;  // 16 inserted-deleted and linked by 15
     Delete;  // 16 inserted-deleted and linked by 15
+    AppendRecord([18,'TestName18']); // again append after delete
   end;
   end;
 end;
 end;
 
 
@@ -390,6 +393,11 @@ begin
   TestChangesCancelUpdates(@DeleteAllInsertChange);
   TestChangesCancelUpdates(@DeleteAllInsertChange);
 end;
 end;
 
 
+procedure TTestBufDatasetStreams.AppendDeleteCancelUpd;
+begin
+  TestChangesCancelUpdates(@AppendDeleteChange);
+end;
+
 procedure TTestBufDatasetStreams.TestBasicsXML;
 procedure TTestBufDatasetStreams.TestBasicsXML;
 var SaveDs: TCustomBufDataset;
 var SaveDs: TCustomBufDataset;
     LoadDs: TCustomBufDataset;
     LoadDs: TCustomBufDataset;