mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-13 12:26:58 +02:00
+ Replaced the array-based record-buffer for a linked-list buffer
git-svn-id: trunk@3111 -
This commit is contained in:
parent
3129dd042e
commit
a75c1e5dd3
@ -18,7 +18,6 @@
|
||||
---------------------------------------------------------------------}
|
||||
|
||||
constructor TBufDataset.Create(AOwner : TComponent);
|
||||
|
||||
begin
|
||||
Inherited Create(AOwner);
|
||||
SetLength(FUpdateBuffer,0);
|
||||
@ -27,34 +26,28 @@ begin
|
||||
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
|
||||
// Only the internal buffers of TDataset provide bookmark information
|
||||
result := AllocMem(FRecordsize);
|
||||
result^ := #1; // this 'deletes' the record
|
||||
// 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));
|
||||
result^ := #1; // this 'deletes' the record
|
||||
@ -70,44 +63,44 @@ procedure TBufDataset.InternalOpen;
|
||||
begin
|
||||
CalcRecordSize;
|
||||
|
||||
FBRecordcount := 0;
|
||||
FBDeletedRecords := 0;
|
||||
FBBuffercount := 0;
|
||||
FBCurrentrecord := -1;
|
||||
// FBRecordcount := 0;
|
||||
// FBDeletedRecords := 0;
|
||||
|
||||
FFirstRecBuf := pointer(IntAllocRecordBuffer);
|
||||
FLastRecBuf := FFirstRecBuf;
|
||||
FCurrentRecBuf := FLastRecBuf;
|
||||
|
||||
FOpen:=True;
|
||||
FIsEOF := false;
|
||||
FIsbOF := true;
|
||||
end;
|
||||
|
||||
procedure TBufDataset.InternalClose;
|
||||
|
||||
var i : integer;
|
||||
var pc : pchar;
|
||||
|
||||
begin
|
||||
FOpen:=False;
|
||||
CancelUpdates;
|
||||
for i := 0 to FBRecordCount-1 do FreeRecordBuffer(FBBuffers[i]);
|
||||
If FBBufferCount > 0 then ReAllocMem(FBBuffers,0);
|
||||
FBRecordcount := 0;
|
||||
FBBuffercount := 0;
|
||||
FCurrentRecBuf := FFirstRecBuf;
|
||||
while assigned(FCurrentRecBuf) do
|
||||
begin
|
||||
pc := pointer(FCurrentRecBuf);
|
||||
FCurrentRecBuf := FCurrentRecBuf^.next;
|
||||
FreeRecordBuffer(pc);
|
||||
end;
|
||||
SetLength(FFieldBufPositions,0);
|
||||
FBCurrentrecord := -1;
|
||||
FIsEOF := true;
|
||||
FIsbOF := true;
|
||||
end;
|
||||
|
||||
procedure TBufDataset.InternalFirst;
|
||||
begin
|
||||
FBCurrentRecord := -1;
|
||||
FIsEOF := false;
|
||||
FCurrentRecBuf := FFirstRecBuf;
|
||||
end;
|
||||
|
||||
procedure TBufDataset.InternalLast;
|
||||
begin
|
||||
repeat
|
||||
until getnextpacket < FPacketRecords;
|
||||
FIsBOF := false;
|
||||
FBCurrentRecord := FBRecordcount;
|
||||
if FLastRecBuf <> FFirstRecBuf then
|
||||
FCurrentRecBuf := FLastRecBuf;
|
||||
end;
|
||||
|
||||
procedure unSetDeleted(NullMask : pbyte); //inline;
|
||||
@ -145,140 +138,82 @@ 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
|
||||
if not assigned(PBufRecLinkItem(FCurrentRecBuf)^.prior) then
|
||||
begin
|
||||
Result := grBOF;
|
||||
FBCurrentRecord := -1;
|
||||
end
|
||||
else
|
||||
begin
|
||||
Dec(FBCurrentRecord);
|
||||
FIsEof := false;
|
||||
FCurrentRecBuf := PBufRecLinkItem(FCurrentRecBuf)^.prior;
|
||||
end;
|
||||
gmCurrent :
|
||||
if (FBCurrentRecord < 0) or (FBCurrentRecord >= FBRecordCount) then
|
||||
if FCurrentRecBuf = FLastRecBuf then
|
||||
Result := grError;
|
||||
gmNext :
|
||||
if FIsEOF then
|
||||
result := grEOF
|
||||
else if FBCurrentRecord >= (FBRecordCount - 1) then
|
||||
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
|
||||
Inc(FBCurrentRecord);
|
||||
FIsBof := false;
|
||||
FCurrentRecBuf := PBufRecLinkItem(FCurrentRecBuf)^.next;
|
||||
end
|
||||
else
|
||||
begin
|
||||
FIsEOF := true;
|
||||
result:=grEOF;
|
||||
end
|
||||
end
|
||||
else
|
||||
begin
|
||||
Inc(FBCurrentRecord);
|
||||
FIsBof := false;
|
||||
FCurrentRecBuf := PBufRecLinkItem(FCurrentRecBuf)^.next;
|
||||
end;
|
||||
end;
|
||||
|
||||
if Result = grOK then
|
||||
begin
|
||||
if GetDeleted(pbyte(FBBuffers[FBCurrentRecord])) then
|
||||
begin
|
||||
if getmode = gmCurrent then
|
||||
if DoCheck then
|
||||
begin
|
||||
Result := grError;
|
||||
DatabaseError(SDeletedRecord);
|
||||
exit;
|
||||
end
|
||||
else
|
||||
getmode := gmnext;
|
||||
Result := GetRecord(Buffer,getmode,DoCheck);
|
||||
exit
|
||||
end;
|
||||
|
||||
with PBufBookmark(Buffer + RecordSize)^ do
|
||||
begin
|
||||
BookmarkData := FBCurrentRecord;
|
||||
BookmarkData := FCurrentRecBuf;
|
||||
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
|
||||
unSetFieldIsNull(NullMask,x);
|
||||
move(FieldUpdBuf^.NewValue^,buffer^,GetFieldSize(FieldDefs[x]));
|
||||
end
|
||||
else
|
||||
SetFieldIsNull(NullMask,x);
|
||||
Inc(Buffer, GetFieldSize(FieldDefs[x]));
|
||||
end;
|
||||
end;
|
||||
move((pointer(FCurrentRecBuf)+sizeof(TBufRecLinkItem))^,buffer^,RecordSize);
|
||||
end
|
||||
else if (Result = grError) and doCheck then
|
||||
DatabaseError('No record');
|
||||
end;
|
||||
|
||||
function TBufDataset.GetRecordUpdateBuffer(rno : integer;var RecUpdBuf : PRecUpdateBuffer) : boolean;
|
||||
function TBufDataset.GetRecordUpdateBuffer : boolean;
|
||||
|
||||
var r : integer;
|
||||
var x : integer;
|
||||
CurrBuff : PChar;
|
||||
|
||||
begin
|
||||
Result := False;
|
||||
for r := 0 to high(FUpdateBuffer) do
|
||||
if (FUpdateBuffer[r].RecordNo = rno) and (@FUpdateBuffer[r] <> FEditBuf) then // Neglect the edit-buffer
|
||||
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
|
||||
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;
|
||||
FCurrentUpdateBuffer := x;
|
||||
break;
|
||||
end;
|
||||
Result := (FCurrentUpdateBuffer < length(FUpdateBuffer)) and (FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData = CurrBuff);
|
||||
end;
|
||||
|
||||
procedure TBufDataset.InternalSetToRecord(Buffer: PChar);
|
||||
begin
|
||||
FBCurrentRecord := PBufBookmark(Buffer + RecordSize)^.BookmarkData;
|
||||
FIsEOF := False;
|
||||
FIsBOF := False;
|
||||
FCurrentRecBuf := PBufBookmark(Buffer + RecordSize)^.BookmarkData;
|
||||
end;
|
||||
|
||||
procedure TBufDataset.SetBookmarkData(Buffer: PChar; Data: Pointer);
|
||||
begin
|
||||
PBufBookmark(Buffer + RecordSize)^.BookmarkData := PInteger(Data)^;
|
||||
PBufBookmark(Buffer + RecordSize)^.BookmarkData := pointer(Data^);
|
||||
end;
|
||||
|
||||
procedure TBufDataset.SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag);
|
||||
@ -288,7 +223,7 @@ end;
|
||||
|
||||
procedure TBufDataset.GetBookmarkData(Buffer: PChar; Data: Pointer);
|
||||
begin
|
||||
PInteger(Data)^ := PBufBookmark(Buffer + RecordSize)^.BookmarkData;
|
||||
pointer(Data^) := PBufBookmark(Buffer + RecordSize)^.BookmarkData;
|
||||
end;
|
||||
|
||||
function TBufDataset.GetBookmarkFlag(Buffer: PChar): TBookmarkFlag;
|
||||
@ -298,35 +233,23 @@ end;
|
||||
|
||||
procedure TBufDataset.InternalGotoBookmark(ABookmark: Pointer);
|
||||
begin
|
||||
FBCurrentRecord := Plongint(ABookmark)^;
|
||||
FIsEOF := False;
|
||||
FIsBOF := False;
|
||||
FCurrentRecBuf := ABookmark;
|
||||
end;
|
||||
|
||||
function TBufDataset.getnextpacket : integer;
|
||||
|
||||
var i : integer;
|
||||
b : boolean;
|
||||
|
||||
pb : pchar;
|
||||
|
||||
begin
|
||||
i := 0;
|
||||
if FBBufferCount < FBRecordCount+FPacketRecords then
|
||||
for i := 0 to FPacketRecords-1 do
|
||||
begin
|
||||
FBBufferCount := FBBuffercount + FPacketRecords;
|
||||
ReAllocMem(FBBuffers,FBBuffercount*SizeOf(PChar));
|
||||
pb := pchar(pointer(FLastRecBuf)+sizeof(TBufRecLinkItem));
|
||||
if (loadbuffer(pb)<>grOk) then break;
|
||||
PBufRecLinkItem(FLastRecBuf)^.next := pointer(IntAllocRecordBuffer);
|
||||
PBufRecLinkItem(PBufRecLinkItem(FLastRecBuf)^.next)^.prior := FLastRecBuf;
|
||||
FLastRecBuf := PBufRecLinkItem(FLastRecBuf)^.next;
|
||||
end;
|
||||
|
||||
repeat
|
||||
FBBuffers[FBRecordCount+i] := intAllocRecordBuffer;
|
||||
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;
|
||||
result := i;
|
||||
end;
|
||||
|
||||
@ -364,14 +287,12 @@ begin
|
||||
|
||||
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;
|
||||
@ -385,9 +306,7 @@ end;
|
||||
|
||||
function TBufDataset.GetFieldData(Field: TField; Buffer: Pointer): Boolean;
|
||||
|
||||
var
|
||||
x : longint;
|
||||
CurrBuff : pchar;
|
||||
var CurrBuff : pchar;
|
||||
|
||||
begin
|
||||
Result := False;
|
||||
@ -395,10 +314,13 @@ begin
|
||||
begin
|
||||
if state = dsOldValue then
|
||||
begin
|
||||
if FApplyingUpdates then
|
||||
CurrBuff := FBBuffers[fbcurrentrecord] // This makes it possible for ApplyUpdates to get values from deleted records
|
||||
else
|
||||
CurrBuff := FBBuffers[GetRecNo];
|
||||
if not GetRecordUpdateBuffer then
|
||||
begin
|
||||
// There is no old value available
|
||||
result := false;
|
||||
exit;
|
||||
end;
|
||||
currbuff := FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer+sizeof(TBufRecLinkItem);
|
||||
end
|
||||
else
|
||||
begin
|
||||
@ -429,11 +351,9 @@ begin
|
||||
end;
|
||||
|
||||
procedure TBufDataset.SetFieldData(Field: TField; Buffer: Pointer);
|
||||
var
|
||||
x : longint;
|
||||
CurrBuff : pointer;
|
||||
NullMask : pbyte;
|
||||
FieldUpdBuf : PFieldUpdateBuffer;
|
||||
|
||||
var CurrBuff : pointer;
|
||||
NullMask : pbyte;
|
||||
|
||||
begin
|
||||
if not (state in [dsEdit, dsInsert]) then
|
||||
@ -446,122 +366,50 @@ begin
|
||||
CurrBuff := ActiveBuffer;
|
||||
NullMask := CurrBuff;
|
||||
|
||||
inc(Currbuff,FNullmaskSize);
|
||||
|
||||
for x := 0 to FieldDefs.count-1 do
|
||||
inc(CurrBuff,FFieldBufPositions[Field.FieldNo-1]);
|
||||
if assigned(buffer) then
|
||||
begin
|
||||
if (Field.FieldName = FieldDefs[x].Name) then
|
||||
begin
|
||||
if assigned(buffer) then
|
||||
begin
|
||||
Move(Buffer^, CurrBuff^, GetFieldSize(FieldDefs[x]));
|
||||
unSetFieldIsNull(NullMask,x);
|
||||
end
|
||||
else
|
||||
SetFieldIsNull(NullMask,x);
|
||||
// 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;
|
||||
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.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^.UpdateKind := ukModify;
|
||||
FEditBuf^.RecordNo := getrecno;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TBufDataset.InternalInsert;
|
||||
|
||||
begin
|
||||
if FBRecordCount > FBBufferCount-1 then
|
||||
begin
|
||||
inc(FBBufferCount);
|
||||
ReAllocMem(FBBuffers,FBBuffercount*SizeOf(PChar));
|
||||
end;
|
||||
|
||||
inc(FBRecordCount);
|
||||
FBCurrentRecord := FBRecordCount -1;
|
||||
FBBuffers[FBCurrentRecord] := intAllocRecordBuffer;
|
||||
fillchar(FBBuffers[FBCurrentRecord]^,FNullmaskSize,255);
|
||||
unSetDeleted(pbyte(FBBuffers[FBCurrentRecord]));
|
||||
fillchar(ActiveBuffer^,FNullmaskSize,255);
|
||||
unSetDeleted(pbyte(ActiveBuffer));
|
||||
|
||||
// cached updates:
|
||||
If not assigned(FEditBuf) then
|
||||
begin
|
||||
SetLength(FUpdateBuffer,length(FUpdateBuffer)+1);
|
||||
FEditBuf := @FUpdateBuffer[high(FUpdateBuffer)];
|
||||
end;
|
||||
FEditBuf^.RecordNo := FBCurrentRecord;
|
||||
FEditBuf^.UpdateKind := ukInsert;
|
||||
|
||||
with PBufBookmark(ActiveBuffer + RecordSize)^ do
|
||||
begin
|
||||
BookmarkData := FBCurrentRecord;
|
||||
BookmarkFlag := bfInserted;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TBufDataset.InternalDelete;
|
||||
|
||||
var tel : integer;
|
||||
var RecToDelete : PBufRecLinkItem;
|
||||
|
||||
begin
|
||||
SetDeleted(pbyte(FBBuffers[FBCurrentRecord]));
|
||||
GetBookmarkData(ActiveBuffer,@RecToDelete);
|
||||
SetDeleted(pbyte(ActiveBuffer));
|
||||
inc(FBDeletedRecords);
|
||||
|
||||
if GetRecordUpdateBuffer(recno,FEditBuf) and (FEditBuf^.UpdateKind = ukInsert) then
|
||||
if RecToDelete <> FFirstRecBuf then RecToDelete^.prior^.next := RecToDelete^.next
|
||||
else FFirstRecBuf := RecToDelete^.next;
|
||||
|
||||
RecToDelete^.next^.prior := RecToDelete^.prior;
|
||||
|
||||
FCurrentRecBuf := RecToDelete^.next;
|
||||
|
||||
if not GetRecordUpdateBuffer then
|
||||
begin
|
||||
if assigned(FEditBuf^.FieldsUpdateBuffer) then
|
||||
for tel := 0 to high(FEditBuf^.FieldsUpdateBuffer) do
|
||||
if not FEditBuf^.FieldsUpdateBuffer[tel].IsNull then
|
||||
freemem(FEditBuf^.FieldsUpdateBuffer[tel].NewValue);
|
||||
setlength(FEditBuf^.FieldsUpdateBuffer,0);
|
||||
FEditBuf^.RecordNo := -1;
|
||||
FCurrentUpdateBuffer := length(FUpdateBuffer);
|
||||
SetLength(FUpdateBuffer,FCurrentUpdateBuffer+1);
|
||||
|
||||
FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer := pchar(RecToDelete);
|
||||
FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData := RecToDelete;
|
||||
end
|
||||
else
|
||||
begin
|
||||
If not assigned(FEditBuf) then
|
||||
begin
|
||||
SetLength(FUpdateBuffer,length(FUpdateBuffer)+1);
|
||||
FEditBuf := @FUpdateBuffer[high(FUpdateBuffer)];
|
||||
end;
|
||||
FEditBuf^.RecordNo := FBCurrentRecord;
|
||||
FEditBuf^.UpdateKind := ukDelete;
|
||||
FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData := FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer;
|
||||
FreeRecordBuffer(pchar(RecToDelete));
|
||||
end;
|
||||
FEditBuf := nil;
|
||||
|
||||
FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind := ukDelete;
|
||||
end;
|
||||
|
||||
|
||||
@ -573,10 +421,9 @@ end;
|
||||
|
||||
procedure TBufDataset.CancelUpdates;
|
||||
|
||||
var r,f : integer;
|
||||
|
||||
begin
|
||||
for r := 0 to high(FUpdateBuffer) do
|
||||
// To be implemented
|
||||
{ for r := 0 to high(FUpdateBuffer) do
|
||||
begin
|
||||
if FUpdateBuffer[r].RecordNo > -1 then
|
||||
if FUpdateBuffer[r].UpdateKind = ukDelete then
|
||||
@ -594,72 +441,46 @@ begin
|
||||
|
||||
end;
|
||||
SetLength(FUpdateBuffer,0);
|
||||
if FOpen then Resync([]);
|
||||
if FOpen then Resync([]);}
|
||||
end;
|
||||
|
||||
procedure TBufDataset.ApplyUpdates;
|
||||
|
||||
var SaveBookmark : Integer;
|
||||
r,i : Integer;
|
||||
buffer : PChar;
|
||||
x : integer;
|
||||
FieldUpdBuf : PFieldUpdateBuffer;
|
||||
NullMask : pbyte;
|
||||
var SaveBookmark : pchar;
|
||||
r : Integer;
|
||||
FailedCount : integer;
|
||||
|
||||
begin
|
||||
CheckBrowseMode;
|
||||
|
||||
// There is no bookmark available if the dataset is empty
|
||||
if not IsEmpty then
|
||||
SaveBookMark := GetRecNo;
|
||||
GetBookmarkData(ActiveBuffer,@SaveBookmark);
|
||||
|
||||
r := 0;
|
||||
FailedCount := 0;
|
||||
while r < Length(FUpdateBuffer) do
|
||||
begin
|
||||
if (@FUpdateBuffer[r] <> FEditBuf) and // Neglect edit-buffer
|
||||
(FUpdateBuffer[r].RecordNo <> -1) then // And the 'deleted' buffers
|
||||
if assigned(FUpdateBuffer[r].BookmarkData) then
|
||||
begin
|
||||
FApplyingUpdates := true;
|
||||
if FUpdateBuffer[r].UpdateKind = ukDelete then
|
||||
InternalGotoBookmark(@(FUpdateBuffer[r].RecordNo))
|
||||
else
|
||||
begin
|
||||
InternalGotoBookMark(@FUpdateBuffer[r].RecordNo);
|
||||
Resync([rmExact,rmCenter]);
|
||||
end;
|
||||
InternalGotoBookmark(FUpdateBuffer[r].BookmarkData);
|
||||
Resync([rmExact,rmCenter]);
|
||||
if ApplyRecUpdate(FUpdateBuffer[r].UpdateKind) 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
|
||||
unSetFieldIsNull(NullMask,x);
|
||||
move(FieldUpdBuf^.NewValue^,buffer^,GetFieldSize(FieldDefs[x]));
|
||||
FreeMem(FieldUpdBuf^.NewValue);
|
||||
end
|
||||
else
|
||||
SetFieldIsNull(NullMask,x);
|
||||
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;
|
||||
FApplyingUpdates := False;
|
||||
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);
|
||||
InternalGotoBookMark(SaveBookMark);
|
||||
Resync([rmExact,rmCenter]);
|
||||
end
|
||||
else
|
||||
@ -668,38 +489,67 @@ end;
|
||||
|
||||
procedure TBufDataset.InternalPost;
|
||||
|
||||
begin
|
||||
if state in [dsEdit, dsInsert] then
|
||||
begin
|
||||
if Length(FUpdateBuffer[High(FUpdateBuffer)].FieldsUpdateBuffer) > 0 then
|
||||
FEditBuf := nil;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TBufDataset.InternalCancel;
|
||||
|
||||
var tel : integer;
|
||||
Var tmpRecBuffer : PBufRecLinkItem;
|
||||
CurrBuff : PChar;
|
||||
|
||||
begin
|
||||
if state in [dsEdit, dsInsert] then
|
||||
if state = dsInsert then
|
||||
begin
|
||||
if state = dsInsert then
|
||||
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
|
||||
SetDeleted(pbyte(FBBuffers[FBCurrentRecord]));
|
||||
SetDeleted(pbyte(ActiveBuffer));
|
||||
inc(FBDeletedRecords);
|
||||
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;
|
||||
FEditBuf^.RecordNo := -1;
|
||||
end
|
||||
else
|
||||
GetBookmarkData(ActiveBuffer,@FCurrentRecBuf);
|
||||
|
||||
// clear the fieldbuffers
|
||||
if assigned(FEditBuf^.FieldsUpdateBuffer) then
|
||||
for tel := 0 to high(FEditBuf^.FieldsUpdateBuffer) do
|
||||
if not FEditBuf^.FieldsUpdateBuffer[tel].IsNull then
|
||||
freemem(FEditBuf^.FieldsUpdateBuffer[tel].NewValue);
|
||||
setlength(FEditBuf^.FieldsUpdateBuffer,0);
|
||||
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;
|
||||
end;
|
||||
|
||||
CurrBuff := pchar(FCurrentRecBuf);
|
||||
inc(Currbuff,sizeof(TBufRecLinkItem));
|
||||
move(ActiveBuffer^,CurrBuff^,RecordSize);
|
||||
end;
|
||||
|
||||
procedure TBufDataset.CalcRecordSize;
|
||||
|
||||
@ -723,8 +573,12 @@ begin
|
||||
end;
|
||||
|
||||
procedure TBufDataset.InternalInitRecord(Buffer: PChar);
|
||||
|
||||
begin
|
||||
FillChar(Buffer^, FRecordSize, #0);
|
||||
|
||||
fillchar(Buffer^,FNullmaskSize,255);
|
||||
unSetDeleted(pbyte(Buffer));
|
||||
end;
|
||||
|
||||
procedure TBufDataset.SetRecNo(Value: Longint);
|
||||
@ -736,7 +590,7 @@ end;
|
||||
function TBufDataset.GetRecNo: Longint;
|
||||
|
||||
begin
|
||||
GetBookmarkData(ActiveBuffer,@Result);
|
||||
// GetBookmarkData(ActiveBuffer,@Result);
|
||||
end;
|
||||
|
||||
function TBufDataset.IsCursorOpen: Boolean;
|
||||
@ -748,7 +602,7 @@ end;
|
||||
Function TBufDataset.GetRecordCount: Longint;
|
||||
|
||||
begin
|
||||
Result := FBRecordCount-FBDeletedRecords;
|
||||
// Result := FBRecordCount-FBDeletedRecords;
|
||||
end;
|
||||
|
||||
Function TBufDataset.Locate(const KeyFields: string; const KeyValues: Variant; options: TLocateOptions) : boolean;
|
||||
@ -768,7 +622,7 @@ var keyfield : TField; // Field to search in
|
||||
|
||||
begin
|
||||
// For now it is only possible to search in one field at the same time
|
||||
result := False;
|
||||
{ result := False;
|
||||
|
||||
keyfield := FieldByName(keyfields);
|
||||
CheckNull := VarIsNull(KeyValues);
|
||||
@ -821,12 +675,9 @@ begin
|
||||
|
||||
if Result then
|
||||
begin
|
||||
bm.BookmarkData := i;
|
||||
// bm.BookmarkData := i;
|
||||
bm.BookmarkFlag := bfCurrent;
|
||||
GotoBookmark(@bm);
|
||||
end;
|
||||
end;}
|
||||
end;
|
||||
|
||||
|
||||
|
||||
|
||||
|
40
fcl/db/db.pp
40
fcl/db/db.pp
@ -1472,50 +1472,43 @@ type
|
||||
|
||||
PBufBookmark = ^TBufBookmark;
|
||||
TBufBookmark = record
|
||||
BookmarkData : integer;
|
||||
BookmarkData : Pointer;
|
||||
BookmarkFlag : TBookmarkFlag;
|
||||
end;
|
||||
|
||||
PFieldUpdateBuffer = ^TFieldUpdateBuffer;
|
||||
TFieldUpdateBuffer = record
|
||||
FieldNo : integer;
|
||||
NewValue : pointer;
|
||||
IsNull : boolean;
|
||||
|
||||
PBufRecLinkItem = ^TBufRecLinkItem;
|
||||
TBufRecLinkItem = record
|
||||
prior : PBufRecLinkItem;
|
||||
next : PBufRecLinkItem;
|
||||
end;
|
||||
|
||||
TFieldsUpdateBuffer = array of TFieldUpdateBuffer;
|
||||
|
||||
PRecUpdateBuffer = ^TRecUpdateBuffer;
|
||||
TRecUpdateBuffer = record
|
||||
RecordNo : integer;
|
||||
FieldsUpdateBuffer : TFieldsUpdateBuffer;
|
||||
UpdateKind : TUpdateKind;
|
||||
BookmarkData : pointer;
|
||||
OldValuesBuffer : pchar;
|
||||
end;
|
||||
|
||||
TRecordsUpdateBuffer = array of TRecUpdateBuffer;
|
||||
|
||||
TBufDataset = class(TDBDataSet)
|
||||
private
|
||||
FBBuffers : TBufferArray;
|
||||
FBRecordCount : integer;
|
||||
FBBufferCount : integer;
|
||||
FBCurrentRecord : integer;
|
||||
FIsEOF : boolean;
|
||||
FIsBOF : boolean;
|
||||
FCurrentRecBuf : PBufRecLinkItem;
|
||||
FLastRecBuf : PBufRecLinkItem;
|
||||
FFirstRecBuf : PBufRecLinkItem;
|
||||
|
||||
FPacketRecords : integer;
|
||||
FRecordSize : Integer;
|
||||
FNullmaskSize : byte;
|
||||
FOpen : Boolean;
|
||||
FUpdateBuffer : TRecordsUpdateBuffer;
|
||||
FEditBuf : PRecUpdateBuffer;
|
||||
FApplyingUpdates: boolean;
|
||||
FBDeletedRecords: integer;
|
||||
FCurrentUpdateBuffer : integer;
|
||||
|
||||
FFieldBufPositions : array of longint;
|
||||
procedure CalcRecordSize;
|
||||
function LoadBuffer(Buffer : PChar): TGetResult;
|
||||
function GetFieldSize(FieldDef : TFieldDef) : longint;
|
||||
function GetRecordUpdateBuffer(rno : integer;var RecUpdBuf : PRecUpdateBuffer) : boolean;
|
||||
function GetFieldUpdateBuffer(fieldno : integer;RecUpdBuf : PRecUpdateBuffer;var FieldUpdBuf : pFieldUpdateBuffer) : boolean;
|
||||
function GetRecordUpdateBuffer : boolean;
|
||||
procedure SetPacketRecords(aValue : integer);
|
||||
function IntAllocRecordBuffer: PChar;
|
||||
protected
|
||||
@ -1531,9 +1524,6 @@ type
|
||||
function getnextpacket : integer;
|
||||
function GetRecordSize: Word; override;
|
||||
procedure InternalPost; override;
|
||||
procedure InternalCancel; override;
|
||||
procedure InternalEdit; override;
|
||||
procedure InternalInsert; override;
|
||||
procedure InternalDelete; override;
|
||||
procedure InternalFirst; override;
|
||||
procedure InternalLast; override;
|
||||
|
Loading…
Reference in New Issue
Block a user