瀏覽代碼

* 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 -

blikblum 15 年之前
父節點
當前提交
5f3905f095
共有 1 個文件被更改,包括 65 次插入42 次删除
  1. 65 42
      packages/fcl-db/src/sqlite/customsqliteds.pas

+ 65 - 42
packages/fcl-db/src/sqlite/customsqliteds.pas

@@ -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;