mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-06 05:10:52 +02:00
* Implemented mergesort BuildIndex
* Added MaxIndexesCount property git-svn-id: trunk@9660 -
This commit is contained in:
parent
6e2af37c48
commit
934d35f27a
@ -160,7 +160,7 @@ type
|
||||
FBlobBuffers : array of PBlobBuffer;
|
||||
FUpdateBlobBuffers: array of PBlobBuffer;
|
||||
|
||||
procedure BuildIndex(AIndex : TBufIndex);
|
||||
procedure BuildIndex(var AIndex : TBufIndex);
|
||||
function GetIndexDefs : TIndexDefs;
|
||||
{$IFDEF ARRAYBUF}
|
||||
procedure AddRecordToIndex(var AIndex: TBufIndex; ARecBuf: pchar);
|
||||
@ -175,6 +175,9 @@ type
|
||||
function GetFieldSize(FieldDef : TFieldDef) : longint;
|
||||
function GetRecordUpdateBuffer : boolean;
|
||||
procedure SetIndexName(const AValue: String);
|
||||
{$IFNDEF ARRAYBUF}
|
||||
procedure SetMaxIndexesCount(const AValue: Integer);
|
||||
{$ENDIF}
|
||||
procedure SetPacketRecords(aValue : integer);
|
||||
function IntAllocRecordBuffer: PChar;
|
||||
procedure DoFilterRecord(var Acceptable: Boolean);
|
||||
@ -239,6 +242,9 @@ type
|
||||
function CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream; override;
|
||||
procedure AddIndex(const AName, AFields : string); virtual;
|
||||
property ChangeCount : Integer read GetChangeCount;
|
||||
{$IFNDEF ARRAYBUF}
|
||||
property MaxIndexesCount : Integer read FMaxIndexesCount write SetMaxIndexesCount;
|
||||
{$ENDIF ARRAYBUF}
|
||||
published
|
||||
property PacketRecords : Integer read FPacketRecords write SetPacketRecords default 10;
|
||||
property OnUpdateError: TResolverErrorEvent read FOnUpdateError write SetOnUpdateError;
|
||||
@ -314,13 +320,38 @@ begin
|
||||
inherited destroy;
|
||||
end;
|
||||
|
||||
procedure TBufDataset.BuildIndex(AIndex: TBufIndex);
|
||||
procedure TBufDataset.BuildIndex(var AIndex: TBufIndex);
|
||||
var PCurRecLinkItem : PBufRecLinkItem;
|
||||
p,l,q : PBufRecLinkItem;
|
||||
i,k,psize,qsize : integer;
|
||||
MergeAmount : integer;
|
||||
PlaceQRec : boolean;
|
||||
|
||||
procedure PlaceNewRec(var e: PBufRecLinkItem; var esize: integer);
|
||||
begin
|
||||
if AIndex.FFirstRecBuf=nil then
|
||||
begin
|
||||
AIndex.FFirstRecBuf:=e;
|
||||
e[AIndex.IndNr].prior:=nil;
|
||||
l:=e;
|
||||
end
|
||||
else
|
||||
begin
|
||||
l[AIndex.IndNr].next:=e;
|
||||
e[AIndex.IndNr].prior:=l;
|
||||
l:=e;
|
||||
end;
|
||||
e := e[AIndex.IndNr].next;
|
||||
dec(esize);
|
||||
end;
|
||||
|
||||
begin
|
||||
// This simply copies the index...
|
||||
{$IFNDEF ARRAYBUF}
|
||||
PCurRecLinkItem:=FIndexes[0].FFirstRecBuf;
|
||||
|
||||
PCurRecLinkItem[AIndex.IndNr].next := PCurRecLinkItem[0].next;
|
||||
PCurRecLinkItem[AIndex.IndNr].prior := PCurRecLinkItem[0].prior;
|
||||
|
||||
if PCurRecLinkItem <> FIndexes[0].FLastRecBuf then
|
||||
begin
|
||||
while PCurRecLinkItem^.next<>FIndexes[0].FLastRecBuf do
|
||||
@ -332,12 +363,106 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
// Set FirstRecBuf and FCurrentRecBuf
|
||||
// Set FirstRecBuf and FCurrentRecBuf
|
||||
AIndex.FFirstRecBuf:=FIndexes[0].FFirstRecBuf;
|
||||
AIndex.FCurrentRecBuf:=FIndexes[0].FCurrentRecBuf;
|
||||
// Link in the FLastRecBuf that belongs to this index
|
||||
AIndex.FCurrentRecBuf:=AIndex.FFirstRecBuf;
|
||||
// Link in the FLastRecBuf that belongs to this index
|
||||
PCurRecLinkItem[AIndex.IndNr].next:=AIndex.FLastRecBuf;
|
||||
AIndex.FLastRecBuf:=PCurRecLinkItem;
|
||||
AIndex.FLastRecBuf[AIndex.IndNr].prior:=PCurRecLinkItem;
|
||||
|
||||
// Mergesort. Used the algorithm as described here by Simon Tatham
|
||||
// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
|
||||
// The comments in the code are from this website.
|
||||
|
||||
// In each pass, we are merging lists of size K into lists of size 2K.
|
||||
// (Initially K equals 1.)
|
||||
k:=1;
|
||||
|
||||
repeat
|
||||
|
||||
// So we start by pointing a temporary pointer p at the head of the list,
|
||||
// and also preparing an empty list L which we will add elements to the end
|
||||
// of as we finish dealing with them.
|
||||
|
||||
p := AIndex.FFirstRecBuf;
|
||||
AIndex.ffirstRecBuf := nil;
|
||||
q := p;
|
||||
MergeAmount := 0;
|
||||
|
||||
// Then:
|
||||
// * If p is null, terminate this pass.
|
||||
while p <> AIndex.FLastRecBuf do
|
||||
begin
|
||||
|
||||
// * Otherwise, there is at least one element in the next pair of length-K
|
||||
// lists, so increment the number of merges performed in this pass.
|
||||
|
||||
inc(MergeAmount);
|
||||
|
||||
// * Point another temporary pointer, q, at the same place as p. Step q along
|
||||
// the list by K places, or until the end of the list, whichever comes
|
||||
// first. Let psize be the number of elements you managed to step q past.
|
||||
|
||||
i:=0;
|
||||
while (i<k) and (q<>AIndex.FLastRecBuf) do
|
||||
begin
|
||||
inc(i);
|
||||
q := q[AIndex.IndNr].next;
|
||||
end;
|
||||
psize :=i;
|
||||
|
||||
// * Let qsize equal K. Now we need to merge a list starting at p, of length
|
||||
// psize, with a list starting at q of length at most qsize.
|
||||
|
||||
qsize:=k;
|
||||
|
||||
// * So, as long as either the p-list is non-empty (psize > 0) or the q-list
|
||||
// is non-empty (qsize > 0 and q points to something non-null):
|
||||
|
||||
while (psize>0) or ((qsize>0) and (q <> AIndex.FLastRecBuf)) do
|
||||
begin
|
||||
// o Choose which list to take the next element from. If either list
|
||||
// is empty, we must choose from the other one. (By assumption, at
|
||||
// least one is non-empty at this point.) If both lists are
|
||||
// non-empty, compare the first element of each and choose the lower
|
||||
// one. If the first elements compare equal, choose from the p-list.
|
||||
// (This ensures that any two elements which compare equal are never
|
||||
// swapped, so stability is guaranteed.)
|
||||
if (psize=0) then
|
||||
PlaceQRec := true
|
||||
else if (qsize=0) or (q = AIndex.FLastRecBuf) then
|
||||
PlaceQRec := False
|
||||
else if CompareText0(pchar(p)+sizeof(TBufRecLinkItem)*FMaxIndexesCount+FFieldBufPositions[AIndex.Fields.FieldNo-1],pchar(q)+sizeof(TBufRecLinkItem)*FMaxIndexesCount+FFieldBufPositions[AIndex.Fields.FieldNo-1],length(pchar(pchar(p)+sizeof(TBufRecLinkItem)*FMaxIndexesCount+FFieldBufPositions[AIndex.Fields.FieldNo-1])),[]) <= 0 then
|
||||
PlaceQRec := False
|
||||
else
|
||||
PlaceQRec := True;
|
||||
|
||||
// o Remove that element, e, from the start of its list, by advancing
|
||||
// p or q to the next element along, and decrementing psize or qsize.
|
||||
// o Add e to the end of the list L we are building up.
|
||||
if PlaceQRec then
|
||||
PlaceNewRec(q,qsize)
|
||||
else
|
||||
PlaceNewRec(p,psize);
|
||||
end;
|
||||
// * Now we have advanced p until it is where q started out, and we have
|
||||
// advanced q until it is pointing at the next pair of length-K lists to
|
||||
// merge. So set p to the value of q, and go back to the start of this loop.
|
||||
p:=q;
|
||||
end;
|
||||
|
||||
// As soon as a pass like this is performed and only needs to do one merge, the
|
||||
// algorithm terminates, and the output list L is sorted. Otherwise, double the
|
||||
// value of K, and go back to the beginning.
|
||||
|
||||
l[AIndex.IndNr].next:=AIndex.FLastRecBuf;
|
||||
|
||||
k:=k*2;
|
||||
|
||||
until MergeAmount = 1;
|
||||
AIndex.FLastRecBuf[AIndex.IndNr].next:=nil;
|
||||
AIndex.FLastRecBuf[AIndex.IndNr].prior:=l;
|
||||
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
@ -703,6 +828,17 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
{$IFNDEF ARRAYBUF}
|
||||
procedure TBufDataset.SetMaxIndexesCount(const AValue: Integer);
|
||||
begin
|
||||
CheckInactive;
|
||||
if AValue > 1 then
|
||||
FMaxIndexesCount:=AValue
|
||||
else
|
||||
DatabaseError(SMinIndexes);
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
procedure TBufDataset.InternalSetToRecord(Buffer: PChar);
|
||||
begin
|
||||
{$IFDEF ARRAYBUF}
|
||||
@ -1738,6 +1874,12 @@ end;
|
||||
procedure TBufDataset.AddIndex(const AName, AFields: string);
|
||||
begin
|
||||
if AFields='' then DatabaseError(SNoIndexFieldNameGiven);
|
||||
|
||||
{$IFNDEF ARRAYBUF}
|
||||
if active and (FIndexesCount=FMaxIndexesCount-1) then
|
||||
DatabaseError(SMaxIndexes);
|
||||
{$ENDIF}
|
||||
|
||||
InternalAddIndex(AName,AFields);
|
||||
// If not all packets are fetched, you can not sort properly.
|
||||
FPacketRecords:=-1;
|
||||
@ -1767,7 +1909,11 @@ begin
|
||||
FIndexes[FIndexesCount-1].FLastRecBuf := FIndexes[FIndexesCount-1].FFirstRecBuf;
|
||||
FIndexes[FIndexesCount-1].FCurrentRecBuf := FIndexes[FIndexesCount-1].FLastRecBuf;
|
||||
BuildIndex(FIndexes[FIndexesCount-1]);
|
||||
end;
|
||||
end
|
||||
{$IFNDEF ARRAYBUF}
|
||||
else if FIndexesCount>FMaxIndexesCount then
|
||||
FMaxIndexesCount := FIndexesCount;
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
procedure TBufDataset.DoFilterRecord(var Acceptable: Boolean);
|
||||
|
@ -91,6 +91,8 @@ Resourcestring
|
||||
SNoUpdateFields = 'There are no fields found to include in the update- or insert-clause';
|
||||
SNotSupported = 'Operation is not supported by this type of database';
|
||||
SDBCreateDropFailed = 'Creation or dropping of database failed';
|
||||
SMaxIndexes = 'The maximum amount of indexes is reached';
|
||||
SMinIndexes = 'The minimum amount of indexes is 1';
|
||||
// These are added for Delphi-compatilility, but not used by the fcl:
|
||||
SFieldIndexError = 'Field index out of range';
|
||||
SIndexFieldMissing = 'Cannot access index field ''%s''';
|
||||
|
Loading…
Reference in New Issue
Block a user