* Cleanup of adding records to bufdatasets with indexes. Mantis #20514, patch by Lacak2.

git-svn-id: trunk@21023 -
This commit is contained in:
marco 2012-04-24 17:47:18 +00:00
parent bf1690458a
commit 7800cd4ff5
2 changed files with 111 additions and 39 deletions

View File

@ -951,11 +951,14 @@ begin
PCurRecLinkItem[DblLinkIndex.IndNr].next := PCurRecLinkItem[0].next; PCurRecLinkItem[DblLinkIndex.IndNr].next := PCurRecLinkItem[0].next;
PCurRecLinkItem[DblLinkIndex.IndNr].prior := PCurRecLinkItem[0].prior; PCurRecLinkItem[DblLinkIndex.IndNr].prior := PCurRecLinkItem[0].prior;
end; end;
end; end
else
// Empty dataset
Exit;
// Set FirstRecBuf and FCurrentRecBuf // Set FirstRecBuf and FCurrentRecBuf
DblLinkIndex.FFirstRecBuf:=Index0.FFirstRecBuf; DblLinkIndex.FFirstRecBuf:=Index0.FFirstRecBuf;
(FCurrentIndex as TDoubleLinkedBufIndex).FCurrentRecBuf:=DblLinkIndex.FFirstRecBuf; DblLinkIndex.FCurrentRecBuf:=DblLinkIndex.FFirstRecBuf;
// Link in the FLastRecBuf that belongs to this index // Link in the FLastRecBuf that belongs to this index
PCurRecLinkItem[DblLinkIndex.IndNr].next:=DblLinkIndex.FLastRecBuf; PCurRecLinkItem[DblLinkIndex.IndNr].next:=DblLinkIndex.FLastRecBuf;
DblLinkIndex.FLastRecBuf[DblLinkIndex.IndNr].prior:=PCurRecLinkItem; DblLinkIndex.FLastRecBuf[DblLinkIndex.IndNr].prior:=PCurRecLinkItem;
@ -975,7 +978,7 @@ begin
// of as we finish dealing with them. // of as we finish dealing with them.
p := DblLinkIndex.FFirstRecBuf; p := DblLinkIndex.FFirstRecBuf;
DblLinkIndex.ffirstRecBuf := nil; DblLinkIndex.FFirstRecBuf := nil;
q := p; q := p;
MergeAmount := 0; MergeAmount := 0;
@ -1079,7 +1082,7 @@ begin
Result:= True; Result:= True;
end; end;
function TCustomBufDataset.intAllocRecordBuffer: TRecordBuffer; function TCustomBufDataset.IntAllocRecordBuffer: TRecordBuffer;
begin begin
// Note: Only the internal buffers of TDataset provide bookmark information // Note: Only the internal buffers of TDataset provide bookmark information
result := AllocMem(FRecordsize+sizeof(TBufRecLinkItem)*FMaxIndexesCount); result := AllocMem(FRecordsize+sizeof(TBufRecLinkItem)*FMaxIndexesCount);
@ -1203,7 +1206,7 @@ procedure TCustomBufDataset.InternalLast;
begin begin
FetchAll; FetchAll;
with FCurrentIndex do with FCurrentIndex do
SetToLastRecord; SetToLastRecord;
end; end;
function TDoubleLinkedBufIndex.GetCurrentRecord: TRecordBuffer; function TDoubleLinkedBufIndex.GetCurrentRecord: TRecordBuffer;
@ -1362,6 +1365,7 @@ procedure TDoubleLinkedBufIndex.InitialiseSpareRecord(const ASpareRecord : TReco
begin begin
FFirstRecBuf := pointer(ASpareRecord); FFirstRecBuf := pointer(ASpareRecord);
FLastRecBuf := FFirstRecBuf; FLastRecBuf := FFirstRecBuf;
FLastRecBuf[IndNr].prior:=nil;
FLastRecBuf[IndNr].next:=FLastRecBuf; FLastRecBuf[IndNr].next:=FLastRecBuf;
FCurrentRecBuf := FLastRecBuf; FCurrentRecBuf := FLastRecBuf;
end; end;
@ -1903,7 +1907,6 @@ end;
procedure TCustomBufDataset.InternalDelete; procedure TCustomBufDataset.InternalDelete;
var i : Integer; var i : Integer;
StartInd : Integer;
RemRec : pointer; RemRec : pointer;
RemRecBookmrk : TBufBookmark; RemRecBookmrk : TBufBookmark;
free_rec: Boolean; free_rec: Boolean;
@ -1913,10 +1916,9 @@ begin
// Remove the record from all active indexes // Remove the record from all active indexes
FCurrentIndex.StoreCurrentRecIntoBookmark(@RemRecBookmrk); FCurrentIndex.StoreCurrentRecIntoBookmark(@RemRecBookmrk);
RemRec := FCurrentIndex.CurrentBuffer; RemRec := FCurrentIndex.CurrentBuffer;
FIndexes[0].RemoveRecordFromIndex(RemRecBookmrk); for i := 0 to FIndexesCount-1 do
if FCurrentIndex=FIndexes[1] then StartInd := 1 else StartInd := 2; if (i<>1) or (FCurrentIndex=FIndexes[i]) then
for i := StartInd to FIndexesCount-1 do FIndexes[i].RemoveRecordFromIndex(RemRecBookmrk);
findexes[i].RemoveRecordFromIndex(RemRecBookmrk);
if not GetActiveRecordUpdateBuffer then if not GetActiveRecordUpdateBuffer then
begin begin
@ -2153,10 +2155,11 @@ end;
procedure TCustomBufDataset.InternalPost; procedure TCustomBufDataset.InternalPost;
Var CurrBuff : TRecordBuffer; Var ABuff : TRecordBuffer;
i : integer; i : integer;
blobbuf : tbufblobfield; blobbuf : tbufblobfield;
NullMask : pbyte; NullMask : pbyte;
ABookmark : PBufBookmark;
begin begin
inherited InternalPost; inherited InternalPost;
@ -2164,38 +2167,43 @@ begin
if assigned(FUpdateBlobBuffers[i]) and (FUpdateBlobBuffers[i]^.FieldNo>0) then if assigned(FUpdateBlobBuffers[i]) and (FUpdateBlobBuffers[i]^.FieldNo>0) then
begin begin
blobbuf.BlobBuffer := FUpdateBlobBuffers[i]; blobbuf.BlobBuffer := FUpdateBlobBuffers[i];
CurrBuff := ActiveBuffer; ABuff := ActiveBuffer;
NullMask := pbyte(CurrBuff); NullMask := PByte(ABuff);
inc(CurrBuff,FFieldBufPositions[FUpdateBlobBuffers[i]^.FieldNo-1]); inc(ABuff,FFieldBufPositions[FUpdateBlobBuffers[i]^.FieldNo-1]);
Move(blobbuf, CurrBuff^, GetFieldSize(FieldDefs[FUpdateBlobBuffers[i]^.FieldNo-1])); Move(blobbuf, ABuff^, GetFieldSize(FieldDefs[FUpdateBlobBuffers[i]^.FieldNo-1]));
unSetFieldIsNull(NullMask,FUpdateBlobBuffers[i]^.FieldNo-1); unSetFieldIsNull(NullMask,FUpdateBlobBuffers[i]^.FieldNo-1);
FUpdateBlobBuffers[i]^.FieldNo := -1; FUpdateBlobBuffers[i]^.FieldNo := -1;
end; end;
if state = dsInsert then if State = dsInsert then
begin begin
if GetBookmarkFlag(ActiveBuffer) = bfEOF then // The active buffer is the newly created TDataset record,
FIndexes[0].ScrollLast // from which the bookmark is set to the record where the new record should be
else // inserted
// The active buffer is the newly created TDataset record, ABookmark := PBufBookmark(ActiveBuffer + FRecordSize);
// from which the bookmark is set to the record where the new record should be // Create the new record buffer
// inserted ABuff := IntAllocRecordBuffer;
InternalSetToRecord(ActiveBuffer);
with FIndexes[0] do // Add new record to all active indexes
for i := 0 to FIndexesCount-1 do
if (i<>1) or (FIndexes[i]=FCurrentIndex) then
begin begin
// Create the new record buffer if ABookmark^.BookmarkFlag = bfEOF then
FCurrentIndex.InsertRecordBeforeCurrentRecord(IntAllocRecordBuffer); // append (at end)
ScrollBackward; FIndexes[i].ScrollLast
// Add the record to the other indexes else
for i := 1 to FIndexesCount-1 do if ((i>1) or (FIndexes[i]=FCurrentIndex)) then // insert (before current record)
FIndexes[i].InsertRecordBeforeCurrentRecord(CurrentRecord); FIndexes[i].GotoBookmark(ABookmark);
FIndexes[i].InsertRecordBeforeCurrentRecord(ABuff);
// new inserted record becomes current record
FIndexes[i].ScrollBackward;
end; end;
// Link the newly created record buffer to the newly created TDataset record // Link the newly created record buffer to the newly created TDataset record
with PBufBookmark(ActiveBuffer + FRecordSize)^ do with ABookmark^ do
begin begin
FCurrentIndex.StoreCurrentRecIntoBookmark(@BookmarkData); FCurrentIndex.StoreCurrentRecIntoBookmark(@BookmarkData);
BookmarkFlag := bfInserted; BookmarkFlag := bfInserted;
@ -2862,9 +2870,7 @@ begin
if Active then if Active then
begin begin
(FIndexes[FIndexesCount-1] as TDoubleLinkedBufIndex).FFirstRecBuf := pointer(IntAllocRecordBuffer); FIndexes[FIndexesCount-1].InitialiseSpareRecord(IntAllocRecordBuffer);
(FIndexes[FIndexesCount-1] as TDoubleLinkedBufIndex).FLastRecBuf := (FIndexes[FIndexesCount-1] as TDoubleLinkedBufIndex).FFirstRecBuf;
(FCurrentIndex as TDoubleLinkedBufIndex).FCurrentRecBuf := (FIndexes[FIndexesCount-1] as TDoubleLinkedBufIndex).FLastRecBuf;
BuildIndex(FIndexes[FIndexesCount-1]); BuildIndex(FIndexes[FIndexesCount-1]);
end end
else if FIndexesCount>FMaxIndexesCount then else if FIndexesCount>FMaxIndexesCount then

View File

@ -104,6 +104,7 @@ type
procedure TestAddDblIndex; procedure TestAddDblIndex;
procedure TestIndexEditRecord; procedure TestIndexEditRecord;
procedure TestIndexAppendRecord;
end; end;
{$endif fpc} {$endif fpc}
@ -1652,10 +1653,11 @@ begin
first; first;
ds.IndexName:='test'; ds.IndexName:='test';
first; first;
LastValue:=FieldByName('name').AsString; LastValue:='';
while not eof do while not eof do
begin begin
CheckTrue(AnsiCompareStr(LastValue,FieldByName('name').AsString)<=0); CheckTrue(AnsiCompareStr(LastValue,FieldByName('name').AsString)<=0);
LastValue:=FieldByName('name').AsString;
Next; Next;
end; end;
end; end;
@ -1851,14 +1853,77 @@ begin
FieldByName('F'+FieldTypeNames[AfieldType]).AsString := 'ZZZ'; FieldByName('F'+FieldTypeNames[AfieldType]).AsString := 'ZZZ';
post; post;
prior; prior;
CheckTrue(AnsiCompareStr('ZZZ',FieldByName('F'+FieldTypeNames[AfieldType]).AsString)>=0); CheckTrue(AnsiCompareStr('ZZZ',FieldByName('F'+FieldTypeNames[AfieldType]).AsString)>=0, 'Prior>');
next; next;
next; next;
CheckTrue(AnsiCompareStr('ZZZ',FieldByName('F'+FieldTypeNames[AfieldType]).AsString)<=0); CheckTrue(AnsiCompareStr('ZZZ',FieldByName('F'+FieldTypeNames[AfieldType]).AsString)<=0, 'Next<');
close; close;
end; end;
end; end;
procedure TTestBufDatasetDBBasics.TestIndexAppendRecord;
var i: integer;
LastValue: string;
begin
with DBConnector.GetNDataset(true,0) as TCustomBufDataset do
begin
MaxIndexesCount:=4;
// add index to closed dataset with no data
AddIndex('testindex','NAME',[]);
IndexName:='testindex';
Open;
// empty dataset and other than default index (default_order) active
CheckTrue(BOF, 'No BOF when opening empty dataset');
CheckTrue(EOF, 'No EOF when opening empty dataset');
// append data at end
for i:=20 downto 0 do
AppendRecord([i, inttostr(i)]);
First;
// insert data at begining
for i:=21 to 22 do
InsertRecord([i, inttostr(i)]);
// ATM new records are not ordered as they are added ?
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');
LastValue := Fields[1].AsString;
Next;
end;
CheckTrue(EOF, 'testindex.No EOF after last record');
// switch back to default index (unordered)
IndexName:='';
First;
for i:=22 downto 0 do
begin
CheckEquals(23-i, RecNo, 'index[0].RecNo:');
CheckEquals(i, Fields[0].AsInteger, 'index[0].Fields[0].Value:');
Next;
end;
CheckTrue(EOF, 'index[0].No EOF after last record');
// add index to opened dataset with data
AddIndex('testindex2','ID',[]);
IndexName:='testindex2';
First;
for i:=0 to 22 do
begin
CheckEquals(1+i, RecNo, 'index2.RecNo:');
CheckEquals(i, Fields[0].AsInteger, 'index2.Fields[0].Value:');
Next;
end;
CheckTrue(EOF, 'index2.No EOF after last record');
Close;
end;
end;
procedure TTestBufDatasetDBBasics.TestIndexFieldNames; procedure TTestBufDatasetDBBasics.TestIndexFieldNames;
var ds : TCustomBufDataset; var ds : TCustomBufDataset;
AFieldType : TFieldType; AFieldType : TFieldType;
@ -2361,7 +2426,8 @@ initialization
RegisterTestDecorator(TDBBasicsTestSetup, TTestDBBasics); RegisterTestDecorator(TDBBasicsTestSetup, TTestDBBasics);
RegisterTestDecorator(TDBBasicsTestSetup, TTestCursorDBBasics); RegisterTestDecorator(TDBBasicsTestSetup, TTestCursorDBBasics);
if uppercase(dbconnectorname)='SQL' then // The SQL connectors are descendents of bufdataset and therefore benefit from testing:
if (uppercase(dbconnectorname)='SQL') or (uppercase(dbconnectorname)='BUFDATASET') then
begin begin
RegisterTestDecorator(TDBBasicsTestSetup, TTestBufDatasetDBBasics); RegisterTestDecorator(TDBBasicsTestSetup, TTestBufDatasetDBBasics);
RegisterTestDecorator(TDBBasicsUniDirectionalTestSetup, TTestUniDirectionalDBBasics); RegisterTestDecorator(TDBBasicsUniDirectionalTestSetup, TTestUniDirectionalDBBasics);