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 Filter;
     Property Filtered;
-    Property Readonly;
+    Property ReadOnly;
     Property AfterCancel;
     Property AfterClose;
     Property AfterDelete;
@@ -1195,6 +1195,8 @@ begin
       begin
       if assigned(OldValuesBuffer) then
         FreeRecordBuffer(OldValuesBuffer);
+      if (UpdateKind = ukDelete) and assigned(BookmarkData.BookmarkData) then
+        FreeRecordBuffer(TRecordBuffer(BookmarkData.BookmarkData));
       end;
     end;
   SetLength(FUpdateBuffer,0);
@@ -1930,7 +1932,7 @@ end;
 
 procedure TCustomBufDataset.InternalDelete;
 var i : Integer;
-    RemRec, FreeRec : pointer;
+    RemRec : pointer;
     RemRecBookmrk : TBufBookmark;
 begin
   InternalSetToRecord(ActiveBuffer);
@@ -1949,15 +1951,16 @@ begin
     FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer := IntAllocRecordBuffer;
     move(RemRec^, FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer^,FRecordSize);
     end
-  else //with FIndexes[0] do
+  else
     begin
     if FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind <> ukModify then
       begin
       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;
   FCurrentIndex.StoreCurrentRecIntoBookmark(@FUpdateBuffer[FCurrentUpdateBuffer].NextBookmarkData);
@@ -2025,7 +2028,8 @@ var StoreRecBM     : TBufBookmark;
           begin
           GotoBookmark(@StoreRecBM);
           if ScrollForward = grEOF then
-            ScrollBackward;
+            if ScrollBackward = grBOF then
+              ScrollLast;  // last record will be removed from index, so move to spare record
           StoreCurrentRecIntoBookmark(@StoreRecBM);
           end;
         FCurrentIndex.RemoveRecordFromIndex(Bm);

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

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