123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780 |
- {
- This file is part of the Free Pascal run time library.
- Copyright (c) 1999-2000 by Michael Van Canneyt, member of the
- Free Pascal development team
- BufDataset implementation
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- { ---------------------------------------------------------------------
- TBufDataSet
- ---------------------------------------------------------------------}
- constructor TBufDataset.Create(AOwner : TComponent);
- begin
- Inherited Create(AOwner);
- SetLength(FUpdateBuffer,0);
- BookmarkSize := sizeof(TBufBookmark);
- FPacketRecords := 10;
- end;
- procedure TBufDataset.SetPacketRecords(aValue : integer);
- begin
- if aValue > 0 then FPacketRecords := aValue
- else DatabaseError(SInvPacketRecordsValue);
- end;
- destructor TBufDataset.Destroy;
- begin
- inherited destroy;
- end;
- Function TBufDataset.GetCanModify: Boolean;
- begin
- Result:= False;
- end;
- function TBufDataset.intAllocRecordBuffer: PChar;
- begin
- // Note: Only the internal buffers of TDataset provide bookmark information
- result := AllocMem(FRecordsize+sizeof(TBufRecLinkItem));
- end;
- function TBufDataset.AllocRecordBuffer: PChar;
- begin
- result := AllocMem(FRecordsize + sizeof(TBufBookmark));
- end;
- procedure TBufDataset.FreeRecordBuffer(var Buffer: PChar);
- begin
- ReAllocMem(Buffer,0);
- end;
- procedure TBufDataset.InternalOpen;
- begin
- CalcRecordSize;
- FBRecordcount := 0;
- FFirstRecBuf := pointer(IntAllocRecordBuffer);
- FLastRecBuf := FFirstRecBuf;
- FCurrentRecBuf := FLastRecBuf;
- FOpen:=True;
- end;
- procedure TBufDataset.InternalClose;
- var pc : pchar;
- begin
- FOpen:=False;
- FCurrentRecBuf := FFirstRecBuf;
- SetLength(FUpdateBuffer,0);
- while assigned(FCurrentRecBuf) do
- begin
- pc := pointer(FCurrentRecBuf);
- FCurrentRecBuf := FCurrentRecBuf^.next;
- FreeRecordBuffer(pc);
- end;
- SetLength(FFieldBufPositions,0);
- end;
- procedure TBufDataset.InternalFirst;
- begin
- FCurrentRecBuf := FFirstRecBuf;
- end;
- procedure TBufDataset.InternalLast;
- begin
- repeat
- until getnextpacket < FPacketRecords;
- if FLastRecBuf <> FFirstRecBuf then
- FCurrentRecBuf := FLastRecBuf;
- end;
- procedure unSetFieldIsNull(NullMask : pbyte;x : longint); //inline;
- begin
- NullMask[x div 8] := (NullMask[x div 8]) and not (1 shl (x mod 8));
- end;
- procedure SetFieldIsNull(NullMask : pbyte;x : longint); //inline;
- begin
- NullMask[x div 8] := (NullMask[x div 8]) or (1 shl (x mod 8));
- end;
- function GetFieldIsNull(NullMask : pbyte;x : longint) : boolean; //inline;
- begin
- result := ord(NullMask[x div 8]) and (1 shl (x mod 8)) > 0
- end;
- function TBufDataset.GetRecord(Buffer: PChar; GetMode: TGetMode; DoCheck: Boolean): TGetResult;
- begin
- Result := grOK;
- case GetMode of
- gmPrior :
- if not assigned(PBufRecLinkItem(FCurrentRecBuf)^.prior) then
- begin
- Result := grBOF;
- end
- else
- begin
- FCurrentRecBuf := PBufRecLinkItem(FCurrentRecBuf)^.prior;
- end;
- gmCurrent :
- if FCurrentRecBuf = FLastRecBuf then
- Result := grError;
- gmNext :
- if FCurrentRecBuf = FLastRecBuf then // Dataset is empty (just opened)
- begin
- if getnextpacket = 0 then result := grEOF;
- end
- else if (PBufRecLinkItem(FCurrentRecBuf)^.next = FLastRecBuf) then
- begin
- if getnextpacket > 0 then
- begin
- FCurrentRecBuf := PBufRecLinkItem(FCurrentRecBuf)^.next;
- end
- else
- begin
- result:=grEOF;
- end
- end
- else
- begin
- FCurrentRecBuf := PBufRecLinkItem(FCurrentRecBuf)^.next;
- end;
- end;
- if Result = grOK then
- begin
- with PBufBookmark(Buffer + RecordSize)^ do
- begin
- BookmarkData := FCurrentRecBuf;
- BookmarkFlag := bfCurrent;
- end;
- move((pointer(FCurrentRecBuf)+sizeof(TBufRecLinkItem))^,buffer^,RecordSize);
- end
- else if (Result = grError) and doCheck then
- DatabaseError('No record');
- end;
- function TBufDataset.GetRecordUpdateBuffer : boolean;
- var x : integer;
- CurrBuff : PChar;
- begin
- GetBookmarkData(ActiveBuffer,@CurrBuff);
- if (FCurrentUpdateBuffer >= length(FUpdateBuffer)) or (FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData <> CurrBuff) then
- for x := 0 to high(FUpdateBuffer) do
- if FUpdateBuffer[x].BookmarkData = CurrBuff then
- begin
- FCurrentUpdateBuffer := x;
- break;
- end;
- Result := (FCurrentUpdateBuffer < length(FUpdateBuffer)) and (FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData = CurrBuff);
- end;
- procedure TBufDataset.InternalSetToRecord(Buffer: PChar);
- begin
- FCurrentRecBuf := PBufBookmark(Buffer + RecordSize)^.BookmarkData;
- end;
- procedure TBufDataset.SetBookmarkData(Buffer: PChar; Data: Pointer);
- begin
- PBufBookmark(Buffer + RecordSize)^.BookmarkData := pointer(Data^);
- end;
- procedure TBufDataset.SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag);
- begin
- PBufBookmark(Buffer + RecordSize)^.BookmarkFlag := Value;
- end;
- procedure TBufDataset.GetBookmarkData(Buffer: PChar; Data: Pointer);
- begin
- pointer(Data^) := PBufBookmark(Buffer + RecordSize)^.BookmarkData;
- end;
- function TBufDataset.GetBookmarkFlag(Buffer: PChar): TBookmarkFlag;
- begin
- Result := PBufBookmark(Buffer + RecordSize)^.BookmarkFlag;
- end;
- procedure TBufDataset.InternalGotoBookmark(ABookmark: Pointer);
- begin
- // note that ABookMark should be a PBufBookmark. But this way it can also be
- // a pointer to a TBufRecLinkItem
- FCurrentRecBuf := pointer(ABookmark^);
- end;
- function TBufDataset.getnextpacket : integer;
- var i : integer;
- pb : pchar;
-
- begin
- i := 0;
- pb := pchar(pointer(FLastRecBuf)+sizeof(TBufRecLinkItem));
- while (i < FPacketRecords) and (loadbuffer(pb) = grOk) do
- begin
- FLastRecBuf^.next := pointer(IntAllocRecordBuffer);
- FLastRecBuf^.next^.prior := FLastRecBuf;
- FLastRecBuf := FLastRecBuf^.next;
- pb := pchar(pointer(FLastRecBuf)+sizeof(TBufRecLinkItem));
- inc(i);
- end;
- FBRecordCount := FBRecordCount + i;
- result := i;
- end;
- function TBufDataset.GetFieldSize(FieldDef : TFieldDef) : longint;
- begin
- case FieldDef.DataType of
- ftString,
- ftFixedChar: result := FieldDef.Size + 1;
- ftSmallint,
- ftInteger,
- ftword : result := sizeof(longint);
- ftBoolean : result := sizeof(wordbool);
- ftBCD : result := sizeof(currency);
- ftFloat : result := sizeof(double);
- ftTime,
- ftDate,
- ftDateTime : result := sizeof(TDateTime)
- else Result := 10
- end;
- end;
- function TBufDataset.LoadBuffer(Buffer : PChar): TGetResult;
- var NullMask : pbyte;
- x : longint;
- begin
- if not Fetch then
- begin
- Result := grEOF;
- Exit;
- end;
- NullMask := pointer(buffer);
- fillchar(Nullmask^,FNullmaskSize,0);
- inc(buffer,FNullmaskSize);
- for x := 0 to FieldDefs.count-1 do
- begin
- if not LoadField(FieldDefs[x],buffer) then
- SetFieldIsNull(NullMask,x);
- inc(buffer,GetFieldSize(FieldDefs[x]));
- end;
- Result := grOK;
- end;
- function TBufDataset.GetFieldData(Field: TField; Buffer: Pointer;
- NativeFormat: Boolean): Boolean;
- begin
- Result := GetFieldData(Field, Buffer);
- end;
- function TBufDataset.GetFieldData(Field: TField; Buffer: Pointer): Boolean;
- var CurrBuff : pchar;
- begin
- Result := False;
- If Field.Fieldno > 0 then // If = 0, then calculated field or something similar
- begin
- if state = dsOldValue then
- begin
- if not GetRecordUpdateBuffer then
- begin
- // There is no old value available
- result := false;
- exit;
- end;
- currbuff := FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer+sizeof(TBufRecLinkItem);
- end
- else
- begin
- CurrBuff := ActiveBuffer;
- if not assigned(CurrBuff) then
- begin
- result := false;
- exit;
- end;
- end;
- if GetFieldIsnull(pbyte(CurrBuff),Field.Fieldno-1) then
- begin
- result := false;
- exit;
- end;
- inc(CurrBuff,FFieldBufPositions[Field.FieldNo-1]);
- if assigned(buffer) then Move(CurrBuff^, Buffer^, GetFieldSize(FieldDefs[Field.FieldNo-1]));
- Result := True;
- end;
- end;
- procedure TBufDataset.SetFieldData(Field: TField; Buffer: Pointer;
- NativeFormat: Boolean);
- begin
- SetFieldData(Field,Buffer);
- end;
- procedure TBufDataset.SetFieldData(Field: TField; Buffer: Pointer);
- var CurrBuff : pointer;
- NullMask : pbyte;
- begin
- if not (state in [dsEdit, dsInsert, dsFilter]) then
- begin
- DatabaseErrorFmt(SNotInEditState,[NAme],self);
- exit;
- end;
- If Field.Fieldno > 0 then // If = 0, then calculated field or something
- begin
- if state = dsFilter then // Set the value into the 'temporary' FLastRecBuf buffer for Locate and Lookup
- CurrBuff := pointer(FLastRecBuf) + sizeof(TBufRecLinkItem)
- else
- CurrBuff := ActiveBuffer;
- NullMask := CurrBuff;
- inc(CurrBuff,FFieldBufPositions[Field.FieldNo-1]);
- if assigned(buffer) then
- begin
- Move(Buffer^, CurrBuff^, GetFieldSize(FieldDefs[Field.FieldNo-1]));
- unSetFieldIsNull(NullMask,Field.FieldNo-1);
- end
- else
- SetFieldIsNull(NullMask,Field.FieldNo-1);
-
- if not (State in [dsCalcFields, dsFilter, dsNewValue]) then
- DataEvent(deFieldChange, Ptrint(Field));
- end;
- end;
- procedure TBufDataset.InternalDelete;
- begin
- GetBookmarkData(ActiveBuffer,@FCurrentRecBuf);
- if FCurrentRecBuf <> FFirstRecBuf then FCurrentRecBuf^.prior^.next := FCurrentRecBuf^.next
- else FFirstRecBuf := FCurrentRecBuf^.next;
- FCurrentRecBuf^.next^.prior := FCurrentRecBuf^.prior;
- if not GetRecordUpdateBuffer then
- begin
- FCurrentUpdateBuffer := length(FUpdateBuffer);
- SetLength(FUpdateBuffer,FCurrentUpdateBuffer+1);
- FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer := pchar(FCurrentRecBuf);
- FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData := FCurrentRecBuf;
- FCurrentRecBuf := FCurrentRecBuf^.next;
- end
- else
- begin
- if FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind = ukModify then
- begin
- FCurrentRecBuf := FCurrentRecBuf^.next;
- FreeRecordBuffer(pchar(FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData));
- FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData := FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer;
- end
- else
- begin
- FCurrentRecBuf := FCurrentRecBuf^.next;
- FreeRecordBuffer(pchar(FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData));
- FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData := nil; //this 'disables' the updatebuffer
- end;
- end;
- dec(FBRecordCount);
- FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind := ukDelete;
- end;
- function TBufDataset.ApplyRecUpdate(UpdateKind : TUpdateKind) : boolean;
- begin
- Result := False;
- end;
- procedure TBufDataset.CancelUpdates;
- var r : Integer;
- begin
- CheckBrowseMode;
- if Length(FUpdateBuffer) > 0 then
- begin
- r := 0;
- while r < Length(FUpdateBuffer) do with FUpdateBuffer[r] do
- begin
- if assigned(FUpdateBuffer[r].BookmarkData) then
- begin
- if UpdateKind = ukModify then
- begin
- move(FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer^,BookmarkData^,RecordSize+sizeof(TBufRecLinkItem));
- FreeRecordBuffer(OldValuesBuffer);
- end
- else if UpdateKind = ukDelete then
- begin
- if assigned(PBufRecLinkItem(BookmarkData)^.prior) then // or else it was the first record
- PBufRecLinkItem(BookmarkData)^.prior^.next := BookmarkData
- else
- FFirstRecBuf := BookmarkData;
- PBufRecLinkItem(BookmarkData)^.next^.prior := BookmarkData;
- inc(FBRecordCount);
- end
- else if UpdateKind = ukInsert then
- begin
- if assigned(PBufRecLinkItem(BookmarkData)^.prior) then // or else it was the first record
- PBufRecLinkItem(BookmarkData)^.prior^.next := PBufRecLinkItem(BookmarkData)^.next
- else
- FFirstRecBuf := PBufRecLinkItem(BookmarkData)^.next;
- PBufRecLinkItem(BookmarkData)^.next^.prior := PBufRecLinkItem(BookmarkData)^.prior;
- // resync won't work if the currentbuffer is freed...
- if FCurrentRecBuf = BookmarkData then FCurrentRecBuf := FCurrentRecBuf^.next;
- FreeRecordBuffer(BookmarkData);
- dec(FBRecordCount);
- end;
- end;
- inc(r);
- end;
- SetLength(FUpdateBuffer,0);
- Resync([]);
- end;
- end;
- procedure TBufDataset.ApplyUpdates;
- var SaveBookmark : pchar;
- r : Integer;
- FailedCount : integer;
- begin
- CheckBrowseMode;
- // There is no bookmark available if the dataset is empty
- if not IsEmpty then
- GetBookmarkData(ActiveBuffer,@SaveBookmark);
- r := 0;
- FailedCount := 0;
- while r < Length(FUpdateBuffer) do
- begin
- if assigned(FUpdateBuffer[r].BookmarkData) then
- begin
- InternalGotoBookmark(@FUpdateBuffer[r].BookmarkData);
- Resync([rmExact,rmCenter]);
- if ApplyRecUpdate(FUpdateBuffer[r].UpdateKind) then
- begin
- FreeRecordBuffer(FUpdateBuffer[r].OldValuesBuffer);
- FUpdateBuffer[r].BookmarkData := nil;
- end
- else
- Inc(FailedCount);
- end;
- inc(r);
- end;
- if failedcount = 0 then
- SetLength(FUpdateBuffer,0);
- if not IsEmpty then
- begin
- InternalGotoBookMark(@SaveBookMark);
- Resync([rmExact,rmCenter]);
- end
- else
- InternalFirst;
- end;
- procedure TBufDataset.InternalPost;
- Var tmpRecBuffer : PBufRecLinkItem;
- CurrBuff : PChar;
- begin
- if state = dsInsert then
- begin
- if GetBookmarkFlag(ActiveBuffer) = bfEOF then
- // Append
- FCurrentRecBuf := FLastRecBuf
- else
- // The active buffer is the newly created TDataset record,
- // from which the bookmark is set to the record where the new record should be
- // inserted
- GetBookmarkData(ActiveBuffer,@FCurrentRecBuf);
- // Create the new record buffer
- tmpRecBuffer := FCurrentRecBuf^.prior;
- FCurrentRecBuf^.prior := pointer(IntAllocRecordBuffer);
- FCurrentRecBuf^.prior^.next := FCurrentRecBuf;
- FCurrentRecBuf := FCurrentRecBuf^.prior;
- If assigned(tmpRecBuffer) then // if not, it's the first record
- begin
- FCurrentRecBuf^.prior := tmpRecBuffer;
- tmpRecBuffer^.next := FCurrentRecBuf
- end
- else
- FFirstRecBuf := FCurrentRecBuf;
- // Link the newly created record buffer to the newly created TDataset record
- with PBufBookmark(ActiveBuffer + RecordSize)^ do
- begin
- BookmarkData := FCurrentRecBuf;
- BookmarkFlag := bfInserted;
- end;
-
- inc(FBRecordCount);
- end
- else
- GetBookmarkData(ActiveBuffer,@FCurrentRecBuf);
- if not GetRecordUpdateBuffer then
- begin
- FCurrentUpdateBuffer := length(FUpdateBuffer);
- SetLength(FUpdateBuffer,FCurrentUpdateBuffer+1);
- FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData := FCurrentRecBuf;
- if state = dsEdit then
- begin
- // Update the oldvalues-buffer
- FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer := intAllocRecordBuffer;
- move(FCurrentRecBuf^,FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer^,RecordSize+sizeof(TBufRecLinkItem));
- FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind := ukModify;
- end
- else
- FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind := ukInsert;
- end;
- CurrBuff := pchar(FCurrentRecBuf);
- inc(Currbuff,sizeof(TBufRecLinkItem));
- move(ActiveBuffer^,CurrBuff^,RecordSize);
- end;
- procedure TBufDataset.CalcRecordSize;
- var x : longint;
- begin
- FNullmaskSize := 1+((FieldDefs.count-1) div 8);
- FRecordSize := FNullmaskSize;
- SetLength(FFieldBufPositions,FieldDefs.count);
- for x := 0 to FieldDefs.count-1 do
- begin
- FFieldBufPositions[x] := FRecordSize;
- inc(FRecordSize, GetFieldSize(FieldDefs[x]));
- end;
- end;
- function TBufDataset.GetRecordSize : Word;
- begin
- result := FRecordSize;
- end;
- procedure TBufDataset.InternalInitRecord(Buffer: PChar);
- begin
- FillChar(Buffer^, FRecordSize, #0);
- fillchar(Buffer^,FNullmaskSize,255);
- end;
- procedure TBufDataset.SetRecNo(Value: Longint);
- var recnr : integer;
- TmpRecBuffer : PBufRecLinkItem;
- begin
- if value > RecordCount then
- begin
- repeat until (getnextpacket < FPacketRecords) or (value <= RecordCount);
- if value > RecordCount then
- begin
- DatabaseError(SNoSuchRecord,self);
- exit;
- end;
- end;
- TmpRecBuffer := FFirstRecBuf;
- for recnr := 1 to value-1 do
- TmpRecBuffer := TmpRecBuffer^.next;
- GotoBookmark(TmpRecBuffer);
- end;
- function TBufDataset.GetRecNo: Longint;
- Var SearchRecBuffer : PBufRecLinkItem;
- TmpRecBuffer : PBufRecLinkItem;
- recnr : integer;
- begin
- GetBookmarkData(ActiveBuffer,@SearchRecBuffer);
- TmpRecBuffer := FFirstRecBuf;
- recnr := 1;
- while TmpRecBuffer <> SearchRecBuffer do
- begin
- inc(recnr);
- TmpRecBuffer := TmpRecBuffer^.next;
- end;
- result := recnr;
- end;
- function TBufDataset.IsCursorOpen: Boolean;
- begin
- Result := FOpen;
- end;
- Function TBufDataset.GetRecordCount: Longint;
- begin
- if state <> dsInsert then Result := FBRecordCount
- else Result := FBRecordCount+1;
- end;
- Function TBufDataset.Locate(const KeyFields: string; const KeyValues: Variant; options: TLocateOptions) : boolean;
- function CompareText0(substr, astr: pchar; len : integer; options: TLocateOptions): integer;
- var
- i : integer; Chr1, Chr2: byte;
- begin
- result := 0;
- i := 0;
- chr1 := 1;
- while (result=0) and (i<len) and (chr1 <> 0) do
- begin
- Chr1 := byte(substr[i]);
- Chr2 := byte(astr[i]);
- inc(i);
- if loCaseInsensitive in options then
- begin
- if Chr1 in [97..122] then
- dec(Chr1,32);
- if Chr2 in [97..122] then
- dec(Chr2,32);
- end;
- result := Chr1 - Chr2;
- end;
- if (result <> 0) and (chr1 = 0) and (loPartialKey in options) then result := 0;
- end;
- var keyfield : TField; // Field to search in
- ValueBuffer : pchar; // Pointer to value to search for, in TField' internal format
- VBLength : integer;
- FieldBufPos : PtrInt; // Amount to add to the record buffer to get the FieldBuffer
- CurrLinkItem: PBufRecLinkItem;
- CurrBuff : pchar;
- bm : TBufBookmark;
- CheckNull : Boolean;
- SaveState : TDataSetState;
- begin
- // For now it is only possible to search in one field at the same time
- result := False;
- keyfield := FieldByName(keyfields);
- CheckNull := VarIsNull(KeyValues);
- if not CheckNull then
- begin
- SaveState := State;
- SetTempState(dsFilter);
- keyfield.Value := KeyValues;
- RestoreState(SaveState);
- FieldBufPos := FFieldBufPositions[keyfield.FieldNo-1];
- VBLength := keyfield.DataSize;
- ValueBuffer := AllocMem(VBLength);
- currbuff := pointer(FLastRecBuf)+sizeof(TBufRecLinkItem)+FieldBufPos;
- move(currbuff^,ValueBuffer^,VBLength);
- end;
- CurrLinkItem := FFirstRecBuf;
- if CheckNull then
- begin
- repeat
- currbuff := pointer(CurrLinkItem)+sizeof(TBufRecLinkItem);
- if GetFieldIsnull(pbyte(CurrBuff),keyfield.Fieldno-1) then
- begin
- result := True;
- break;
- end;
- CurrLinkItem := CurrLinkItem^.next;
- if CurrLinkItem = FLastRecBuf then getnextpacket;
- until CurrLinkItem = FLastRecBuf;
- end
- else if keyfield.DataType = ftString then
- begin
- repeat
- currbuff := pointer(CurrLinkItem)+sizeof(TBufRecLinkItem);
- if not GetFieldIsnull(pbyte(CurrBuff),keyfield.Fieldno-1) then
- begin
- inc(CurrBuff,FieldBufPos);
- if CompareText0(ValueBuffer,CurrBuff,VBLength,options) = 0 then
- begin
- result := True;
- break;
- end;
- end;
- CurrLinkItem := CurrLinkItem^.next;
- if CurrLinkItem = FLastRecBuf then getnextpacket;
- until CurrLinkItem = FLastRecBuf;
- end
- else
- begin
- repeat
- currbuff := pointer(CurrLinkItem)+sizeof(TBufRecLinkItem);
- if not GetFieldIsnull(pbyte(CurrBuff),keyfield.Fieldno-1) then
- begin
- inc(CurrBuff,FieldBufPos);
- if CompareByte(ValueBuffer^,CurrBuff^,VBLength) = 0 then
- begin
- result := True;
- break;
- end;
- end;
- CurrLinkItem := CurrLinkItem^.next;
- if CurrLinkItem = FLastRecBuf then getnextpacket;
- until CurrLinkItem = FLastRecBuf;
- end;
- if Result then
- begin
- bm.BookmarkData := CurrLinkItem;
- bm.BookmarkFlag := bfCurrent;
- GotoBookmark(@bm);
- end;
- ReAllocmem(ValueBuffer,0);
- end;
|