mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-28 21:40:34 +02:00
* Cleanup of adding records to bufdatasets with indexes. Mantis #20514, patch by Lacak2.
git-svn-id: trunk@21023 -
This commit is contained in:
parent
bf1690458a
commit
7800cd4ff5
@ -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
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user