123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542 |
- {
- $Id$
- 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);
- // temporary set it here
- FPacketRecords := 10;
- end;
- destructor TBufDataset.Destroy;
- begin
- inherited destroy;
- end;
- Function TBufDataset.GetCanModify: Boolean;
- begin
- Result:= False;
- 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;
- FBBuffercount := 0;
- FBCurrentrecord := -1;
- FOpen:=True;
- FIsEOF := false;
- FIsbOF := true;
- end;
- procedure TBufDataset.InternalClose;
- var i : integer;
- begin
- FOpen:=False;
- CancelUpdates;
- for i := 0 to FBRecordCount-1 do FreeRecordBuffer(FBBuffers[i]);
- If FBRecordCount > 0 then ReAllocMem(FBBuffers,0);
- FBRecordcount := 0;
- FBBuffercount := 0;
- FBCurrentrecord := -1;
- FIsEOF := true;
- FIsbOF := true;
- end;
- procedure TBufDataset.InternalFirst;
- begin
- FBCurrentRecord := -1;
- FIsEOF := false;
- end;
- procedure TBufDataset.InternalLast;
- begin
- repeat
- until getnextpacket < FPacketRecords;
- FIsBOF := false;
- FBCurrentRecord := FBRecordcount;
- end;
- function TBufDataset.GetRecord(Buffer: PChar; GetMode: TGetMode; DoCheck: Boolean): TGetResult;
- var x : longint;
- RecUpdBuf : PRecUpdateBuffer;
- FieldUpdBuf : PFieldUpdateBuffer;
- NullMask : pbyte;
- begin
- Result := grOK;
- case GetMode of
- gmPrior :
- if FIsBOF then
- result := grBOF
- else if FBCurrentRecord <= 0 then
- begin
- Result := grBOF;
- FBCurrentRecord := -1;
- end
- else
- begin
- Dec(FBCurrentRecord);
- FIsEof := false;
- end;
- gmCurrent :
- if (FBCurrentRecord < 0) or (FBCurrentRecord >= RecordCount) then
- Result := grError;
- gmNext :
- if FIsEOF then
- result := grEOF
- else if FBCurrentRecord >= (FBRecordCount - 1) then
- begin
- if getnextpacket > 0 then
- begin
- Inc(FBCurrentRecord);
- FIsBof := false;
- end
- else
- begin
- FIsEOF := true;
- result:=grEOF;
- end
- end
- else
- begin
- Inc(FBCurrentRecord);
- FIsBof := false;
- end;
- end;
- if Result = grOK then
- begin
- with PBufBookmark(Buffer + RecordSize)^ do
- begin
- BookmarkData := FBCurrentRecord;
- BookmarkFlag := bfCurrent;
- end;
- move(FBBuffers[FBCurrentRecord]^,buffer^,RecordSize);
- // Cached Updates:
- If GetRecordUpdateBuffer(FBCurrentRecord,RecUpdBuf) then
- begin
- NullMask := pbyte(buffer);
- inc(buffer,FNullmaskSize);
- for x := 0 to FieldDefs.count-1 do
- begin
- if GetFieldUpdateBuffer(x,RecUpdBuf,FieldUpdBuf) then
- If not FieldUpdBuf^.IsNull then
- begin
- NullMask[x div 8] := (NullMask[x div 8]) and not (1 shl (x mod 8));
- move(FieldUpdBuf^.NewValue^,buffer^,GetFieldSize(FieldDefs[x]));
- end
- else
- NullMask[x div 8] := (NullMask[x div 8]) or (1 shl (x mod 8));
- Inc(Buffer, GetFieldSize(FieldDefs[x]));
- end;
- end;
- end
- else if (Result = grError) and doCheck then
- DatabaseError('No record');
- end;
- function TBufDataset.GetRecordUpdateBuffer(rno : integer;var RecUpdBuf : PRecUpdateBuffer) : boolean;
- var r : integer;
- begin
- Result := False;
- for r := 0 to high(FUpdateBuffer) do
- if (FUpdateBuffer[r].RecordNo = rno) and (@FUpdateBuffer[r] <> FEditBuf) then // Neglect the edit-buffer
- begin
- RecUpdBuf := @FUpdateBuffer[r];
- Result := True;
- Break;
- end;
- end;
- function TBufDataset.GetFieldUpdateBuffer(fieldno : integer;RecUpdBuf : PRecUpdateBuffer;var FieldUpdBuf : pFieldUpdateBuffer) : boolean;
- var f : integer;
- begin
- Result := False;
- for f := 0 to High(RecUpdBuf^.FieldsUpdateBuffer) do
- if RecUpdBuf^.FieldsUpdateBuffer[f].FieldNo = fieldno then
- begin
- FieldUpdBuf := @RecUpdBuf^.FieldsUpdateBuffer[f];
- Result := True;
- Break;
- end;
- end;
- procedure TBufDataset.InternalSetToRecord(Buffer: PChar);
- begin
- FBCurrentRecord := PBufBookmark(Buffer + RecordSize)^.BookmarkData;
- FIsEOF := False;
- FIsBOF := False;
- end;
- procedure TBufDataset.SetBookmarkData(Buffer: PChar; Data: Pointer);
- begin
- PBufBookmark(Buffer + RecordSize)^.BookmarkData := PInteger(Data)^;
- end;
- procedure TBufDataset.SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag);
- begin
- PBufBookmark(Buffer + RecordSize)^.BookmarkFlag := Value;
- end;
- procedure TBufDataset.GetBookmarkData(Buffer: PChar; Data: Pointer);
- begin
- PInteger(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
- FBCurrentRecord := Plongint(ABookmark)^;
- FIsEOF := False;
- FIsBOF := False;
- end;
- function TBufDataset.getnextpacket : integer;
- var i : integer;
- b : boolean;
- begin
- i := 0;
- if FPacketRecords > 0 then
- begin
- FBBufferCount := FBBuffercount + FPacketRecords;
- ReAllocMem(FBBuffers,FBBuffercount*SizeOf(PChar));
- repeat
- FBBuffers[FBRecordCount+i] := AllocRecordBuffer;
- b := (loadbuffer(FBBuffers[FBRecordCount+i])<>grOk);
- inc(i);
- until (i = FPacketRecords) or b;
- if b then
- begin
- dec(i);
- FreeRecordBuffer(FBBuffers[FBRecordCount+i]);
- end;
- FBRecordCount := FBRecordCount + i;
- end;
- result := i;
- end;
- function TBufDataset.GetFieldSize(FieldDef : TFieldDef) : longint;
- begin
- case FieldDef.DataType of
- ftString : result := FieldDef.Size + 1;
- ftSmallint,
- ftInteger,
- ftword : result := sizeof(longint);
- ftBoolean : result := sizeof(boolean);
- 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
- NullMask[x div 8] := (NullMask[x div 8]) or (1 shl (x mod 8));
- inc(buffer,GetFieldSize(FieldDefs[x]));
- end;
- Result := grOK;
- end;
- function TBufDataset.GetFieldData(Field: TField; Buffer: Pointer): Boolean;
- var
- x : longint;
- CurrBuff : pchar;
- begin
- Result := False;
-
- If Field.Fieldno > 0 then // If = 0, then calculated field or something similar
- begin
- if state = dsOldValue then
- CurrBuff := FBBuffers[GetRecNo]
- else
- CurrBuff := ActiveBuffer;
- if ord(currbuff[(Field.Fieldno-1) div 8]) and (1 shl ((Field.Fieldno-1) mod 8)) > 0 then
- begin
- result := false;
- exit;
- end;
- inc(Currbuff,FNullmaskSize);
- for x := 0 to FieldDefs.count-1 do
- begin
- if (Field.FieldName = FieldDefs[x].Name) then
- begin
- Move(CurrBuff^, Buffer^, GetFieldSize(FieldDefs[x]));
- Result := True;
- Break;
- end
- else Inc(CurrBuff, GetFieldSize(FieldDefs[x]));
- end;
- end;
- end;
- procedure TBufDataset.SetFieldData(Field: TField; Buffer: Pointer);
- var
- x : longint;
- CurrBuff : pointer;
- NullMask : pbyte;
- FieldUpdBuf : PFieldUpdateBuffer;
- begin
- If Field.Fieldno > 0 then // If = 0, then calculated field or something
- begin
- CurrBuff := ActiveBuffer;
- NullMask := CurrBuff;
- inc(Currbuff,FNullmaskSize);
- for x := 0 to FieldDefs.count-1 do
- begin
- if (Field.FieldName = FieldDefs[x].Name) then
- begin
- if assigned(buffer) then
- begin
- Move(Buffer^, CurrBuff^, GetFieldSize(FieldDefs[x]));
- NullMask[x div 8] := (NullMask[x div 8]) and not (1 shl (x mod 8));
- end
- else
- NullMask[x div 8] := (NullMask[x div 8]) or (1 shl (x mod 8));
- // cached updates
- with FEditBuf^ do
- begin
- if not GetFieldUpdateBuffer(x,FEditBuf,FieldUpdBuf) then
- begin
- SetLength(FieldsUpdateBuffer,length(FieldsUpdateBuffer)+1);
- FieldUpdBuf := @FieldsUpdateBuffer[high(FieldsUpdateBuffer)];
- GetMem(FieldUpdBuf^.NewValue,GetFieldSize(FieldDefs[x]));
- FieldUpdBuf^.FieldNo := x;
- end;
- if assigned(buffer) then
- begin
- Move(Buffer^, FieldUpdBuf^.NewValue^, GetFieldSize(FieldDefs[x]));
- FieldUpdBuf^.IsNull := False;
- end
- else FieldUpdBuf^.IsNull := True;
- end;
- Break;
- end
- else Inc(CurrBuff, GetFieldSize(FieldDefs[x]));
- end;
- if not (State in [dsCalcFields, dsFilter, dsNewValue]) then
- DataEvent(deFieldChange, Ptrint(Field));
- end;
- end;
- procedure TBufDataset.InternalEdit;
- begin
- if not GetRecordUpdateBuffer(recno,FEditBuf) then
- begin
- If not assigned(FEditBuf) then
- begin
- SetLength(FUpdateBuffer,length(FUpdateBuffer)+1);
- FEditBuf := @FUpdateBuffer[high(FUpdateBuffer)];
- end;
- FEditBuf^.RecordNo := getrecno;
- end;
- end;
- function TBufDataset.ApplyRecUpdate : boolean;
- begin
- Result := False;
- end;
- procedure TBufDataset.CancelUpdates;
- var r,f : integer;
- begin
- for r := 0 to high(FUpdateBuffer) do
- for f := 0 to high(FUpdateBuffer[r].FieldsUpdateBuffer) do
- FreeMem(FUpdateBuffer[r].FieldsUpdateBuffer[f].newvalue);
- SetLength(FUpdateBuffer,0);
- end;
- procedure TBufDataset.ApplyUpdates;
- var SaveBookmark : Integer;
- r,i : Integer;
- buffer : PChar;
- x : integer;
- FieldUpdBuf : PFieldUpdateBuffer;
- NullMask : pbyte;
- begin
- SaveBookMark := GetRecNo;
-
- r := 0;
- while r < Length(FUpdateBuffer) do
- begin
- if @FUpdateBuffer[r] <> FEditBuf then // Neglect edit-buffer
- begin
- SetRecNo(FUpdateBuffer[r].RecordNo);
- if ApplyRecUpdate then
- begin
- buffer := FBBuffers[FUpdateBuffer[r].RecordNo];
- NullMask := pbyte(buffer);
- inc(buffer,FNullmaskSize);
- for x := 0 to FieldDefs.count-1 do
- begin
- if GetFieldUpdateBuffer(x,@FUpdateBuffer[r],FieldUpdBuf) then
- If not FieldUpdBuf^.IsNull then
- begin
- NullMask[x div 8] := (NullMask[x div 8]) and not (1 shl (x mod 8));
- move(FieldUpdBuf^.NewValue^,buffer^,GetFieldSize(FieldDefs[x]));
- FreeMem(FieldUpdBuf^.NewValue);
- end
- else
- NullMask[x div 8] := (NullMask[x div 8]) or (1 shl (x mod 8));
- Inc(Buffer, GetFieldSize(FieldDefs[x]));
- end;
- for i := r to high(FUpdateBuffer)-1 do
- FUpdateBuffer[i] := FupdateBuffer[i+1];
- dec(r);
- SetLength(FUpdateBuffer,high(FUpdateBuffer));
- end;
- end;
- inc(r);
- end;
- Refresh;
- SetRecNo(SaveBookMark);
- end;
- procedure TBufDataset.InternalPost;
- begin
- if state=dsEdit then
- begin
- if Length(FUpdateBuffer[High(FUpdateBuffer)].FieldsUpdateBuffer) > 0 then
- FEditBuf := nil;
- end;
- end;
- procedure TBufDataset.CalcRecordSize;
- var x : longint;
- begin
- FNullmaskSize := 1+((FieldDefs.count-1) div 8);
- FRecordSize := FNullmaskSize;
- for x := 0 to FieldDefs.count-1 do
- inc(FRecordSize, GetFieldSize(FieldDefs[x]));
- end;
- function TBufDataset.GetRecordSize : Word;
- begin
- result := FRecordSize;
- end;
- procedure TBufDataset.InternalInitRecord(Buffer: PChar);
- begin
- FillChar(Buffer^, FRecordSize, #0);
- end;
- procedure TBufDataset.SetRecNo(Value: Longint);
- begin
- GotoBookmark(@value);
- end;
- function TBufDataset.GetRecNo: Longint;
- begin
- GetBookmarkData(ActiveBuffer,@Result);
- end;
- function TBufDataset.IsCursorOpen: Boolean;
- begin
- Result := FOpen;
- end;
- Function TBufDataset.GetRecordCount: Longint;
- begin
- Result := FBRecordCount;
- end;
|