View Issue Details

IDProjectCategoryView StatusLast Update
0022387LazarusDatabasepublic2014-05-05 21:52
ReporterLudo Brands Assigned ToJuha Manninen  
PrioritynormalSeveritymajorReproducibilityalways
Status resolvedResolutionsuspended 
Product Version1.1 (SVN) 
Summary0022387: [Patch] TDBLookup.Initialize causes sigsegv when ListLink.Dataset is closed and DefaultFields true
DescriptionZeosdataset frees TDataset.Fields when the dataset is closed and DefaultFields=true. TDBLookup.Initialize opens temporarily a closed link dataset stores FListField and closes it again before calling FetchLookupData. FetchLookupData reopens the link dataset and calls then FListField.DisplayText on a FListField that points to a freed TField from the first open. This results in a sigsegv.

The patch fetches FListField in the beginning of FetchLookupData to be sure the FListField is current. I also does this after LinkGetBookMark to avoid opening twice the dataset temporarily.
An alternative, more complex, patch would be to invalidate FListField when the link dataset is closed and only re-fetch FListField when invalidated.

TagsNo tags attached.
Fixed in Revision
LazTarget-
Widgetset
Attached Files

Activities

2012-07-07 14:29

 

dblookup.diff (5,786 bytes)   
Index: include/dblookup.inc
===================================================================
--- include/dblookup.inc	(revision 37892)
+++ include/dblookup.inc	(working copy)
@@ -114,6 +114,56 @@
     Result := FKeyFieldNames;
 end;
 
+procedure TDBLookup.GetListField;
+var
+  ListFields: TList;
+begin
+  if (FKeyFieldNames > '') and Assigned(FListLink.Dataset) and not (csLoading in FListLink.DataSet.ComponentState) then
+  begin
+    FListLinkTmpSetActive := not FListLink.DataSet.Active;
+    if FListLinkTmpSetActive then
+    try
+      FListLink.DataSet.Open;
+    except
+      FListLinkTmpSetActive := False;
+      Exit;
+    end;
+    ListFields := TList.Create;
+    try
+      if FListLink.DataSet.Active then
+      begin
+        FListLink.DataSet.GetFieldList(ListFields, FListFieldName);
+        FListLink.DataSet.GetFieldList(FKeyFields, FKeyFieldNames);
+        if FHasLookUpField then
+        begin
+          FListField := FListLink.DataSet.FindField(FControlLink.Field.LookupResultField);
+          if (Assigned(FListField) and (ListFields.IndexOf(FListField) < 0)) then
+            ListFields.Insert(0, FListField);
+          if (ListFields.Count > 0) then
+            FListField := TField(ListFields[0]);
+        end else
+        begin
+          if ((FKeyFields.Count > 0) and (ListFields.Count = 0)) then
+            ListFields.Add(FKeyFields[0]);
+          if ((FListFieldIndex > -1) and (FListFieldIndex < ListFields.Count)) then
+            FListField := TField(ListFields[FListFieldIndex])
+          else
+            FListField := TField(ListFields[0]);
+        end;
+        if Assigned(FListField) then
+          FListLink.FieldName:= FListField.FieldName;
+      end;
+    finally
+      ListFields.Free;
+      if FListLinkTmpSetActive then
+      begin
+        FListLink.DataSet.Active := False;
+        FListLinkTmpSetActive := False;
+      end;
+    end;
+  end;
+end;
+
 function TDBLookup.GetListSource: TDataSource;
 begin
   if FHasLookUpField then
@@ -223,21 +273,26 @@
     Exit;
   FControlItems.Clear;
   ListLinkDataSet := FListLink.DataSet;
-  if not (Assigned(ListLinkDataSet) and Assigned(FListField)) then
+  if not (Assigned(ListLinkDataSet) and (FKeyFieldNames > '')
+      and not (csLoading in ListLinkDataSet.ComponentState)) then
     Exit;
   LinkGetBookMark;
   try
-    //needed to handle sqldb.TSQLQuery that does not has a reliable recordcount after Open
-    ListLinkDataSet.Last;
-    ListLinkDataSet.First;
-    SetLength(FListKeys, ListLinkDataSet.RecordCount);
-    i := 0;
-    while not ListLinkDataSet.EOF do
+    GetListField;
+    if assigned(FListField) then
     begin
-      FListKeys[i] := ListLinkDataSet.FieldValues[FKeyFieldNames];
-      Inc(i);
-      FControlItems.Add(FListField.DisplayText);
-      ListLinkDataSet.Next;
+      //needed to handle sqldb.TSQLQuery that does not has a reliable recordcount after Open
+      ListLinkDataSet.Last;
+      ListLinkDataSet.First;
+      SetLength(FListKeys, ListLinkDataSet.RecordCount);
+      i := 0;
+      while not ListLinkDataSet.EOF do
+      begin
+        FListKeys[i] := ListLinkDataSet.FieldValues[FKeyFieldNames];
+        Inc(i);
+        FControlItems.Add(FListField.DisplayText);
+        ListLinkDataSet.Next;
+      end;
     end;
   finally
     LinkGotoBookMark;
@@ -245,8 +300,6 @@
 end;
 
 procedure TDBLookup.Initialize(AControlDataLink: TFieldDataLink; AControlItems: TStrings);
-var
-  ListFields: TList;
 begin
   FDataFields.Clear;
   FKeyFields.Clear;
@@ -278,52 +331,7 @@
   end;
   if not FHasLookUpField then
     ChangeListLinkDataSource(FListSource);
-
-  if (FKeyFieldNames > '') and Assigned(FListLink.Dataset) and not (csLoading in FListLink.DataSet.ComponentState) then
-  begin
-    FListLinkTmpSetActive := not FListLink.DataSet.Active;
-    if FListLinkTmpSetActive then
-    try
-      FListLink.DataSet.Open;
-    except
-      FListLinkTmpSetActive := False;
-      Exit;
-    end;
-    ListFields := TList.Create;
-    try
-      if FListLink.DataSet.Active then
-      begin
-        FListLink.DataSet.GetFieldList(ListFields, FListFieldName);
-        FListLink.DataSet.GetFieldList(FKeyFields, FKeyFieldNames);
-        if FHasLookUpField then
-        begin
-          FListField := FListLink.DataSet.FindField(AControlDataLink.Field.LookupResultField);
-          if (Assigned(FListField) and (ListFields.IndexOf(FListField) < 0)) then
-            ListFields.Insert(0, FListField);
-          if (ListFields.Count > 0) then
-            FListField := TField(ListFields[0]);
-        end else
-        begin
-          if ((FKeyFields.Count > 0) and (ListFields.Count = 0)) then
-            ListFields.Add(FKeyFields[0]);
-          if ((FListFieldIndex > -1) and (FListFieldIndex < ListFields.Count)) then
-            FListField := TField(ListFields[FListFieldIndex])
-          else
-            FListField := TField(ListFields[0]);
-        end;
-        if Assigned(FListField) then
-          FListLink.FieldName:= FListField.FieldName;
-      end;
-    finally
-      ListFields.Free;
-      if FListLinkTmpSetActive then
-      begin
-        FListLink.DataSet.Active := False;
-        FListLinkTmpSetActive := False;
-      end;
-    end;
-    FetchLookupData;
-  end;
+  FetchLookupData;
 end;
 
 function TDBLookup.KeyFieldValue: Variant;
Index: dbctrls.pp
===================================================================
--- dbctrls.pp	(revision 37892)
+++ dbctrls.pp	(working copy)
@@ -138,6 +138,7 @@
     procedure EditingChange(Sender: TObject);
     procedure FetchLookupData;
     function GetKeyFieldName: string;
+    procedure GetListField;
     function GetListSource: TDataSource;
     procedure LinkGetBookMark;
     procedure LinkGotoBookMark;
dblookup.diff (5,786 bytes)   

Juha Manninen

2013-04-28 15:45

developer   ~0067221

Ludo, is this issue still valid?
I tried to apply your patch but it was not possible, the code has changed too much.

Juha Manninen

2014-05-05 21:52

developer   ~0074797

Suspending. Probably not a valid issue any more.

Issue History

Date Modified Username Field Change
2012-07-07 14:29 Ludo Brands New Issue
2012-07-07 14:29 Ludo Brands File Added: dblookup.diff
2013-04-28 15:42 Juha Manninen Assigned To => Juha Manninen
2013-04-28 15:42 Juha Manninen Status new => assigned
2013-04-28 15:45 Juha Manninen LazTarget => -
2013-04-28 15:45 Juha Manninen Note Added: 0067221
2013-04-28 15:45 Juha Manninen Status assigned => feedback
2014-05-05 21:52 Juha Manninen Note Added: 0074797
2014-05-05 21:52 Juha Manninen Status feedback => resolved
2014-05-05 21:52 Juha Manninen Resolution open => suspended