* Fix crash when using a lookup field of memo type (correctly calculate field offset)

* Ensure Field Change event is always called in Write mode (Write method is not called if new text is empty)

git-svn-id: trunk@14120 -
This commit is contained in:
blikblum 2009-11-09 03:54:39 +00:00
parent d111f9220d
commit 5f3905f095

View File

@ -56,17 +56,22 @@ type
Previous: PDataRecord;
end;
{ TDSStream }
//todo: refactor into two or three classes
TDSStream = class(TStream)
private
FActiveItem: PDataRecord;
FEditItem: PDataRecord;
FDataset: TCustomSqliteDataset;
FFieldRow: PChar;
FField: TField;
FFieldOffset: Integer;
FRowSize: Integer;
FPosition: LongInt;
FWriteMode: Boolean;
public
constructor Create(Dataset: TCustomSqliteDataset; Field: TField);
constructor Create(Dataset: TCustomSqliteDataset; Field: TField;
FieldOffset: Integer; EditItem: PDataRecord; WriteMode: Boolean);
destructor Destroy; override;
function Write(const Buffer; Count: LongInt): LongInt; override;
function Read(var Buffer; Count: LongInt): LongInt; override;
function Seek(Offset: LongInt; Origin: Word): LongInt; override;
@ -329,23 +334,29 @@ end;
// TDSStream
constructor TDSStream.Create(Dataset: TCustomSqliteDataset; Field: TField);
constructor TDSStream.Create(Dataset: TCustomSqliteDataset; Field: TField;
FieldOffset: Integer; EditItem: PDataRecord; WriteMode: Boolean);
begin
inherited Create;
//FPosition := 0;
FDataset := Dataset;
FField := Field;
if Field.FieldNo >= 0 then
FFieldOffset := Field.FieldNo - 1
else
FFieldOffset := Dataset.FieldDefs.Count + Dataset.FCalcFieldList.IndexOf(Field);
FActiveItem := PPDataRecord(Dataset.ActiveBuffer)^;
FFieldRow := FActiveItem^.Row[FFieldOffset];
FFieldOffset := FieldOffset;
FWriteMode := WriteMode;
FEditItem := EditItem;
FFieldRow := FEditItem^.Row[FFieldOffset];
if FFieldRow <> nil then
FRowSize := StrLen(FFieldRow);
//else
// FRowSize := 0;
end;
end;
destructor TDSStream.Destroy;
begin
if FWriteMode and not (FDataset.State in [dsCalcFields, dsFilter, dsNewValue]) then
FDataset.DataEvent(deFieldChange, PtrInt(FField));
inherited Destroy;
end;
function TDSStream.Seek(Offset: LongInt; Origin: Word): LongInt;
begin
@ -362,30 +373,29 @@ var
NewRow: PChar;
begin
Result := Count;
if Count = 0 then
Exit;
//FRowSize is always 0 when FPosition = 0,
//so there's no need to check FPosition
NewRow := StrAlloc(FRowSize + Count + 1);
(NewRow + Count + FRowSize)^ := #0;
if FRowSize > 0 then
Move(FFieldRow^, NewRow^, FRowSize);
Move(Buffer, (NewRow + FRowSize)^, Count);
FActiveItem^.Row[FFieldOffset] := NewRow;
StrDispose(FFieldRow);
{$ifdef DEBUG_SQLITEDS}
WriteLn('##TDSStream.Write##');
WriteLn(' FPosition(Before): ', FPosition);
WriteLn(' FRowSize(Before): ', FRowSize);
WriteLn(' FPosition(After): ', FPosition+Count);
WriteLn(' FRowSize(After): ', StrLen(NewRow));
//WriteLn(' Stream Value: ',NewRow);
{$endif}
FFieldRow := NewRow;
FRowSize := StrLen(NewRow);
Inc(FPosition, Count);
if not (FDataset.State in [dsCalcFields, dsFilter, dsNewValue]) then
FDataset.DataEvent(deFieldChange, PtrInt(FField));
if Count > 0 then
begin
//FRowSize is always 0 when FPosition = 0,
//so there's no need to check FPosition
NewRow := StrAlloc(FRowSize + Count + 1);
(NewRow + Count + FRowSize)^ := #0;
if FRowSize > 0 then
Move(FFieldRow^, NewRow^, FRowSize);
Move(Buffer, (NewRow + FRowSize)^, Count);
FEditItem^.Row[FFieldOffset] := NewRow;
StrDispose(FFieldRow);
{$ifdef DEBUG_SQLITEDS}
WriteLn('##TDSStream.Write##');
WriteLn(' FPosition(Before): ', FPosition);
WriteLn(' FRowSize(Before): ', FRowSize);
WriteLn(' FPosition(After): ', FPosition+Count);
WriteLn(' FRowSize(After): ', StrLen(NewRow));
//WriteLn(' Stream Value: ',NewRow);
{$endif}
FFieldRow := NewRow;
FRowSize := StrLen(NewRow);
Inc(FPosition, Count);
end;
end;
function TDSStream.Read(var Buffer; Count: Longint): LongInt;
@ -456,18 +466,31 @@ begin
end;
function TCustomSqliteDataset.CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream;
var
FieldOffset: Integer;
EditItem: PDataRecord;
begin
if Field.FieldNo >= 0 then
begin
if Mode = bmWrite then
EditItem := FCacheItem
else
EditItem := PPDataRecord(ActiveBuffer)^;
FieldOffset := Field.FieldNo - 1;
end
else
begin
EditItem := PPDataRecord(CalcBuffer)^;
FieldOffset := FieldDefs.Count + FCalcFieldList.IndexOf(Field);
end;
if Mode = bmWrite then
begin
if not (State in [dsEdit, dsInsert]) then
begin
DatabaseErrorFmt(SNotEditing,[Name],Self);
Exit;
end;
StrDispose(FCacheItem^.Row[Field.FieldNo - 1]);
FCacheItem^.Row[Field.FieldNo - 1] := nil;
if not (State in [dsEdit, dsInsert, dsCalcFields]) then
DatabaseErrorFmt(SNotEditing, [Name], Self);
StrDispose(EditItem^.Row[FieldOffset]);
EditItem^.Row[FieldOffset] := nil;
end;
Result := TDSStream.Create(Self, Field);
Result := TDSStream.Create(Self, Field, FieldOffset, EditItem, Mode = bmWrite);
end;
procedure TCustomSqliteDataset.DoBeforeClose;