Browse Source

--- Merging r21280 into '.':
U packages/fcl-db/tests/testbufdatasetstreams.pas
U packages/fcl-db/src/base/bufdataset.pas
--- Merging r21640 into '.':
U packages/fcl-db/tests/testspecifictbufdataset.pas
U packages/fcl-db/src/base/dataset.inc
--- Merging r21643 into '.':
U packages/fcl-db/src/sqldb/postgres/pqeventmonitor.pp
--- Merging r21674 into '.':
U packages/fcl-db/tests/bufdatasettoolsunit.pas

# revisions: 21280,21640,21643,21674
r21280 | marco | 2012-05-12 22:15:52 +0200 (Sat, 12 May 2012) | 11 lines
Changed paths:
M /trunk/packages/fcl-db/src/base/bufdataset.pas
M /trunk/packages/fcl-db/tests/testbufdatasetstreams.pas


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
r21640 | joost | 2012-06-18 11:48:52 +0200 (Mon, 18 Jun 2012) | 1 line
Changed paths:
M /trunk/packages/fcl-db/src/base/dataset.inc
M /trunk/packages/fcl-db/tests/testspecifictbufdataset.pas

* Createdataset should not create fielddefs for calculated or lookup fields
r21643 | marco | 2012-06-18 13:15:18 +0200 (Mon, 18 Jun 2012) | 4 lines
Changed paths:
M /trunk/packages/fcl-db/src/sqldb/postgres/pqeventmonitor.pp

* do not set fregistered directoy since that hampers registerevents().
Patch by Ludo, Mantis #22244
r21674 | marco | 2012-06-21 17:31:21 +0200 (Thu, 21 Jun 2012) | 2 lines
Changed paths:
M /trunk/packages/fcl-db/tests/bufdatasettoolsunit.pas

* Add bufdataset support to testsuite for ftFixedChar and ftFmtBCD field types
mantis #22297 patch by Lacak2

git-svn-id: branches/fixes_2_6@22443 -

marco 13 years ago
parent
commit
a57f3e4e38

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

@@ -556,7 +556,7 @@ type
     Property AutoCalcFields;
     Property Filter;
     Property Filtered;
-    Property Readonly;
+    Property ReadOnly;
     Property AfterCancel;
     Property AfterClose;
     Property AfterDelete;
@@ -1181,6 +1181,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);
@@ -1916,7 +1918,7 @@ end;
 
 procedure TCustomBufDataset.InternalDelete;
 var i : Integer;
-    RemRec, FreeRec : pointer;
+    RemRec : pointer;
     RemRecBookmrk : TBufBookmark;
 begin
   InternalSetToRecord(ActiveBuffer);
@@ -1935,15 +1937,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);
@@ -2011,7 +2014,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 - 7
packages/fcl-db/src/base/dataset.inc

@@ -904,15 +904,16 @@ begin
     FieldDefs.BeginUpdate;
     try
       for i := 0 to Fields.Count-1 do with fields[i] do
-        begin
-        with TFieldDef.Create(FieldDefs,FieldName,DataType,Size,Required,i+1) do
+        if not (FieldKind in [fkCalculated,fkLookup]) then // Do not add fielddefs for calculated/lookup fields.
           begin
-          if Required then Attributes := attributes + [faRequired];
-          if ReadOnly then Attributes := attributes + [faReadOnly];
-          if DataType = ftBCD then precision := (fields[i] as TBCDField).Precision
-          else if DataType = ftFMTBcd then precision := (fields[i] as TFMTBCDField).Precision;
+          with TFieldDef.Create(FieldDefs,FieldName,DataType,Size,Required,FieldDefs.Count+1) do
+            begin
+            if Required then Attributes := attributes + [faRequired];
+            if ReadOnly then Attributes := attributes + [faReadOnly];
+            if DataType = ftBCD then precision := (fields[i] as TBCDField).Precision
+            else if DataType = ftFMTBcd then precision := (fields[i] as TFMTBCDField).Precision;
+            end;
           end;
-        end;
     finally
       FieldDefs.EndUpdate;
       end;

+ 0 - 1
packages/fcl-db/src/sqldb/postgres/pqeventmonitor.pp

@@ -122,7 +122,6 @@ end;
 
 procedure TPQEventMonitor.SetRegistered(AValue: Boolean);
 begin
-  FRegistered := AValue;
   if not (csDesigning in ComponentState) then
     if AValue then
       RegisterEvents

+ 11 - 3
packages/fcl-db/tests/bufdatasettoolsunit.pas

@@ -37,6 +37,9 @@ type
 
 implementation
 
+uses
+  StrUtils, FmtBCD;
+
 type
 
   { TPersistentBufDataSet }
@@ -85,6 +88,7 @@ var BufDataset  : TPersistentBufDataSet;
 
 begin
   BufDataset := TPersistentBufDataSet.Create(nil);
+  BufDataset.Name := 'NDataset';
   BufDataset.FieldDefs.Add('ID',ftInteger);
   BufDataset.FieldDefs.Add('NAME',ftString,50);
   BufDataset.CreateDataset;
@@ -109,20 +113,20 @@ var BufDataset  : TPersistentBufDataSet;
     i      : integer;
 
 begin
-  // Values >= 24:00:00.000 can't be handled by bufdataset
+  // Values >= 24:00:00.000 can't be handled by StrToTime function
   testTimeValues[2] := '23:59:59.000';
   testTimeValues[3] := '23:59:59.003';
 
   BufDataset := TPersistentBufDataSet.Create(nil);
   with BufDataset do
     begin
+    Name := 'FieldDataset';
     UniDirectional := FUniDirectional;
     FieldDefs.Add('ID',ftInteger);
     FieldDefs.Add('FSTRING',ftString,10);
     FieldDefs.Add('FSMALLINT',ftSmallint);
     FieldDefs.Add('FINTEGER',ftInteger);
-    // Not supported by BufDataset:
-    // FieldDefs.Add('FWORD',ftWord);
+    FieldDefs.Add('FWORD',ftWord);
     FieldDefs.Add('FBOOLEAN',ftBoolean);
     FieldDefs.Add('FFLOAT',ftFloat);
     FieldDefs.Add('FCURRENCY',ftCurrency);
@@ -131,6 +135,8 @@ begin
     FieldDefs.Add('FTIME',ftTime);
     FieldDefs.Add('FDATETIME',ftDateTime);
     FieldDefs.Add('FLARGEINT',ftLargeint);
+    FieldDefs.Add('FFIXEDCHAR',ftFixedChar,10);
+    FieldDefs.Add('FFMTBCD',ftFmtBCD);
     CreateDataset;
     Open;
     for i := 0 to testValuesCount-1 do
@@ -147,6 +153,8 @@ begin
       FieldByName('FDATE').AsDateTime := StrToDateTime(testDateValues[i], Self.FormatSettings);
       FieldByName('FTIME').AsDateTime := StrToTime(testTimeValues[i], Self.FormatSettings);
       FieldByName('FLARGEINT').AsLargeInt := testLargeIntValues[i];
+      FieldByName('FFIXEDCHAR').AsString := PadRight(testStringValues[i], 10);
+      FieldByName('FFMTBCD').AsBCD := StrToBCD(testFmtBCDValues[i], Self.FormatSettings);
       Post;
     end;
     BufDataset.TempFileName:=GetTempFileName;

+ 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;

+ 47 - 0
packages/fcl-db/tests/testspecifictbufdataset.pas

@@ -32,6 +32,7 @@ type
   published
     procedure CreateDatasetFromFielddefs;
     procedure CreateDatasetFromFields;
+    procedure TestCreationDatasetWithCalcFields;
   end;
 
 implementation
@@ -109,6 +110,52 @@ begin
   TestDataset(ds);
 end;
 
+procedure TTestSpecificTBufDataset.TestCreationDatasetWithCalcFields;
+var ds : TBufDataset;
+    f: TField;
+    i: integer;
+begin
+  ds := TBufDataset.Create(nil);
+  try
+    F := TIntegerField.Create(ds);
+    F.FieldName:='ID';
+    F.DataSet:=ds;
+    F := TStringField.Create(ds);
+    F.FieldName:='NAME';
+    F.DataSet:=ds;
+    F.Size:=50;
+
+    F := TStringField.Create(ds);
+    F.FieldKind:=fkCalculated;
+    F.FieldName:='NAME_CALC';
+    F.DataSet:=ds;
+    F.Size:=50;
+
+    F := TStringField.Create(ds);
+    F.FieldKind:=fkLookup;
+    F.FieldName:='NAME_LKP';
+    F.LookupDataSet:=DBConnector.GetNDataset(5);
+    F.KeyFields:='ID';
+    F.LookupKeyFields:='ID';
+    F.LookupResultField:='NAME';
+    F.DataSet:=ds;
+    F.Size:=50;
+
+    DS.CreateDataset;
+
+    TestDataset(ds);
+
+    for i := 0 to ds.FieldDefs.Count-1 do
+      begin
+      CheckNotEquals(ds.FieldDefs[i].Name,'NAME_CALC');
+      CheckNotEquals(ds.FieldDefs[i].Name,'NAME_LKP');
+      end;
+    DS.Close;
+  finally
+    ds.Free;
+  end;
+end;
+
 initialization
 {$ifdef fpc}