mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-13 23:42:34 +02:00
fcl-db: base: improve Blob handling. When writting empty blob set null on. raise data event FieldChange after data are written, not before.
git-svn-id: trunk@25411 -
This commit is contained in:
parent
d03507671d
commit
f24d30105e
@ -41,15 +41,18 @@ type
|
|||||||
|
|
||||||
TBufBlobStream = class(TStream)
|
TBufBlobStream = class(TStream)
|
||||||
private
|
private
|
||||||
|
FField : TBlobField;
|
||||||
|
FDataSet : TCustomBufDataset;
|
||||||
FBlobBuffer : PBlobBuffer;
|
FBlobBuffer : PBlobBuffer;
|
||||||
FPosition : ptrint;
|
FPosition : ptrint;
|
||||||
FDataset : TCustomBufDataset;
|
FModified : boolean;
|
||||||
protected
|
protected
|
||||||
|
function Seek(Offset: Longint; Origin: Word): Longint; override;
|
||||||
function Read(var Buffer; Count: Longint): Longint; override;
|
function Read(var Buffer; Count: Longint): Longint; override;
|
||||||
function Write(const Buffer; Count: Longint): Longint; override;
|
function Write(const Buffer; Count: Longint): Longint; override;
|
||||||
function Seek(Offset: Longint; Origin: Word): Longint; override;
|
|
||||||
public
|
public
|
||||||
constructor Create(Field: TBlobField; Mode: TBlobStreamMode);
|
constructor Create(Field: TBlobField; Mode: TBlobStreamMode);
|
||||||
|
destructor Destroy; override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TCustomBufDataset }
|
{ TCustomBufDataset }
|
||||||
@ -2330,11 +2333,14 @@ begin
|
|||||||
ABuff := ActiveBuffer;
|
ABuff := ActiveBuffer;
|
||||||
NullMask := PByte(ABuff);
|
NullMask := PByte(ABuff);
|
||||||
|
|
||||||
inc(ABuff,FFieldBufPositions[FUpdateBlobBuffers[i]^.FieldNo-1]);
|
inc(ABuff,FFieldBufPositions[blobbuf.BlobBuffer^.FieldNo-1]);
|
||||||
Move(blobbuf, ABuff^, GetFieldSize(FieldDefs[FUpdateBlobBuffers[i]^.FieldNo-1]));
|
Move(blobbuf, ABuff^, GetFieldSize(FieldDefs[blobbuf.BlobBuffer^.FieldNo-1]));
|
||||||
unSetFieldIsNull(NullMask,FUpdateBlobBuffers[i]^.FieldNo-1);
|
if blobbuf.BlobBuffer^.Size = 0 then
|
||||||
|
SetFieldIsNull(NullMask, blobbuf.BlobBuffer^.FieldNo-1)
|
||||||
|
else
|
||||||
|
unSetFieldIsNull(NullMask, blobbuf.BlobBuffer^.FieldNo-1);
|
||||||
|
|
||||||
FUpdateBlobBuffers[i]^.FieldNo := -1;
|
blobbuf.BlobBuffer^.FieldNo := -1;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if State = dsInsert then
|
if State = dsInsert then
|
||||||
@ -2582,6 +2588,8 @@ begin
|
|||||||
ABlobBuffer := Nil;
|
ABlobBuffer := Nil;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TBufBlobStream }
|
||||||
|
|
||||||
function TBufBlobStream.Seek(Offset: Longint; Origin: Word): Longint;
|
function TBufBlobStream.Seek(Offset: Longint; Origin: Word): Longint;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
@ -2617,6 +2625,7 @@ begin
|
|||||||
move(buffer,ptr^,count);
|
move(buffer,ptr^,count);
|
||||||
inc(FBlobBuffer^.Size,count);
|
inc(FBlobBuffer^.Size,count);
|
||||||
inc(FPosition,count);
|
inc(FPosition,count);
|
||||||
|
FModified := True;
|
||||||
Result := count;
|
Result := count;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -2625,12 +2634,14 @@ constructor TBufBlobStream.Create(Field: TBlobField; Mode: TBlobStreamMode);
|
|||||||
var bufblob : TBufBlobField;
|
var bufblob : TBufBlobField;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
FDataset := Field.DataSet as TCustomBufDataset;
|
FField := Field;
|
||||||
|
FDataSet := Field.DataSet as TCustomBufDataset;
|
||||||
|
with FDataSet do
|
||||||
if Mode = bmRead then
|
if Mode = bmRead then
|
||||||
begin
|
begin
|
||||||
if not Field.GetData(@bufblob) then
|
if not Field.GetData(@bufblob) then
|
||||||
DatabaseError(SFieldIsNull);
|
DatabaseError(SFieldIsNull);
|
||||||
if not assigned(bufblob.BlobBuffer) then with FDataSet do
|
if not assigned(bufblob.BlobBuffer) then
|
||||||
begin
|
begin
|
||||||
FBlobBuffer := GetNewBlobBuffer;
|
FBlobBuffer := GetNewBlobBuffer;
|
||||||
bufblob.BlobBuffer := FBlobBuffer;
|
bufblob.BlobBuffer := FBlobBuffer;
|
||||||
@ -2639,7 +2650,7 @@ begin
|
|||||||
else
|
else
|
||||||
FBlobBuffer := bufblob.BlobBuffer;
|
FBlobBuffer := bufblob.BlobBuffer;
|
||||||
end
|
end
|
||||||
else if Mode=bmWrite then with FDataSet as TCustomBufDataset do
|
else if Mode=bmWrite then
|
||||||
begin
|
begin
|
||||||
FBlobBuffer := GetNewWriteBlobBuffer;
|
FBlobBuffer := GetNewWriteBlobBuffer;
|
||||||
FBlobBuffer^.FieldNo := Field.FieldNo;
|
FBlobBuffer^.FieldNo := Field.FieldNo;
|
||||||
@ -2647,9 +2658,24 @@ begin
|
|||||||
FBlobBuffer^.OrgBufID := bufblob.BlobBuffer^.OrgBufID
|
FBlobBuffer^.OrgBufID := bufblob.BlobBuffer^.OrgBufID
|
||||||
else
|
else
|
||||||
FBlobBuffer^.OrgBufID := -1;
|
FBlobBuffer^.OrgBufID := -1;
|
||||||
|
FModified := True;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
destructor TBufBlobStream.Destroy;
|
||||||
|
begin
|
||||||
|
if FModified then
|
||||||
|
begin
|
||||||
|
// if TBufBlobStream was requested, but no data was written, then Size = 0;
|
||||||
|
// used by TBlobField.Clear, so in this case set Field to null in InternalPost
|
||||||
|
//FField.Modified := True; // should be set to True, but TBlobField.Modified is never reset
|
||||||
|
|
||||||
|
if not (FDataSet.State in [dsFilter, dsCalcFields, dsNewValue]) then
|
||||||
|
FDataSet.DataEvent(deFieldChange, Ptrint(FField));
|
||||||
|
end;
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
function TCustomBufDataset.CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream;
|
function TCustomBufDataset.CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream;
|
||||||
|
|
||||||
var bufblob : TBufBlobField;
|
var bufblob : TBufBlobField;
|
||||||
@ -2669,9 +2695,6 @@ begin
|
|||||||
DatabaseErrorFmt(SNotEditing,[Name],self);
|
DatabaseErrorFmt(SNotEditing,[Name],self);
|
||||||
|
|
||||||
result := TBufBlobStream.Create(Field as TBlobField, bmWrite);
|
result := TBufBlobStream.Create(Field as TBlobField, bmWrite);
|
||||||
|
|
||||||
if not (State in [dsCalcFields, dsFilter, dsNewValue]) then
|
|
||||||
DataEvent(deFieldChange, Ptrint(Field));
|
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -2928,7 +2928,7 @@ end;
|
|||||||
procedure TBlobField.Clear;
|
procedure TBlobField.Clear;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
GetBlobStream(bmWrite).free;
|
GetBlobStream(bmWrite).Free;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ unit TestBufDatasetStreams;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
fpcunit, testutils, testregistry, testdecorator,
|
fpcunit, testregistry,
|
||||||
Classes, SysUtils, db, BufDataset;
|
Classes, SysUtils, db, BufDataset;
|
||||||
|
|
||||||
type
|
type
|
||||||
@ -71,6 +71,7 @@ type
|
|||||||
procedure TestDeleteAllInsertXML;
|
procedure TestDeleteAllInsertXML;
|
||||||
procedure TestStreamingBlobFieldsXML;
|
procedure TestStreamingBlobFieldsXML;
|
||||||
procedure TestStreamingBigBlobFieldsXML;
|
procedure TestStreamingBigBlobFieldsXML;
|
||||||
|
procedure TestStreamingNullFieldsXML;
|
||||||
procedure TestStreamingCalculatedFieldsXML;
|
procedure TestStreamingCalculatedFieldsXML;
|
||||||
|
|
||||||
procedure TestAppendDeleteBIN;
|
procedure TestAppendDeleteBIN;
|
||||||
@ -473,8 +474,8 @@ begin
|
|||||||
SaveDS.First;
|
SaveDS.First;
|
||||||
while not LoadDS.EOF do
|
while not LoadDS.EOF do
|
||||||
begin
|
begin
|
||||||
AssertEquals(LoadDS.FieldByName('FBLOB').AsString,SaveDS.FieldByName('FBLOB').AsString);
|
AssertEquals(SaveDS.FieldByName('FBLOB').AsString, LoadDS.FieldByName('FBLOB').AsString);
|
||||||
AssertEquals(LoadDS.FieldByName('FMEMO').AsString,SaveDS.FieldByName('FMEMO').AsString);
|
AssertEquals(SaveDS.FieldByName('FMEMO').AsString, LoadDS.FieldByName('FMEMO').AsString);
|
||||||
LoadDS.Next;
|
LoadDS.Next;
|
||||||
SaveDS.Next;
|
SaveDS.Next;
|
||||||
end;
|
end;
|
||||||
@ -547,6 +548,44 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TTestBufDatasetStreams.TestStreamingNullFieldsXML;
|
||||||
|
var
|
||||||
|
SaveDs: TCustomBufDataset;
|
||||||
|
LoadDs: TCustomBufDataset;
|
||||||
|
i: integer;
|
||||||
|
begin
|
||||||
|
SaveDs := DBConnector.GetFieldDataset(true) as TCustomBufDataset;
|
||||||
|
with SaveDs do
|
||||||
|
begin
|
||||||
|
Open;
|
||||||
|
Next;
|
||||||
|
Edit;
|
||||||
|
// set all fields to null
|
||||||
|
for i:=0 to FieldCount-1 do
|
||||||
|
Fields[i].Clear;
|
||||||
|
Post;
|
||||||
|
// check if they are null
|
||||||
|
for i:=0 to FieldCount-1 do
|
||||||
|
AssertTrue(Fields[i].FieldName, Fields[i].IsNull);
|
||||||
|
SaveToFile(TestXMLFileName, dfXML);
|
||||||
|
end;
|
||||||
|
|
||||||
|
LoadDs := TCustomBufDataset.Create(nil);
|
||||||
|
try
|
||||||
|
LoadDs.LoadFromFile(TestXMLFileName);
|
||||||
|
SaveDs.First;
|
||||||
|
while not SaveDs.EOF do
|
||||||
|
begin
|
||||||
|
for i:=0 to SaveDs.FieldCount-1 do
|
||||||
|
AssertEquals(SaveDs.Fields[i].FieldName, SaveDs.Fields[i].IsNull, LoadDs.Fields[i].IsNull);
|
||||||
|
LoadDs.Next;
|
||||||
|
SaveDs.Next;
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
LoadDs.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TTestBufDatasetStreams.TestStreamingCalculatedFieldsXML;
|
procedure TTestBufDatasetStreams.TestStreamingCalculatedFieldsXML;
|
||||||
var
|
var
|
||||||
ADataset: TCustomBufDataset;
|
ADataset: TCustomBufDataset;
|
||||||
|
Loading…
Reference in New Issue
Block a user