Delphi - How to free Memory from a TDataSet?

2.6k views Asked by At

D2010, Win7 64bit. Hello,

I have a buttonClick event with needs to process a TDataSet opened in another routine... GetDBGenericData.

The function GetDBGenericData returns a TDataSet. This routine basically takes a tQuery component, sets it's SQL property, and opens it. It then returns the TDataSet to my buttonclick.

procedure TForm1.Button2Click(Sender: TObject);
var
DS : TDataSet;
begin

DS := TDataSet.Create(nil);
DS := GetDBGenericData(dbSOURCE, 'LIST_ALL_SCHEMAS', [] );

while Not DS.EOF do
   begin
   ShowMessage(DS.FieldByName('USERNAME').AsString);
   DS.Next;
   end;

DS.Close;
DS.Free;

My problem is -- Understanding DS. I am creating it here in this routine. I am "assigning" it to a TDataSet that points to a component. If I DON'T Free it, I have a memory leak (as reported by EurekaLog). If I do free it, I get an AV the next time I run this routine. (specifically inside the GetDBGenericData routine).

What I think is happening is that DS is getting assigned to (as opposed to copying) to the TDataSet that is being returned, so in effect, I am FREEING BOTH DS in this routine, and the tQuery in GetDBGenericData, when I do a free.

How do I "break" the linkage, and then delete the memory associated to ONLY the one I am dynamically creating.

Thanks, GS

1

There are 1 answers

0
Ken White On BEST ANSWER

If your DS variable is being assigned another TDataSet by GetDBGenericData, you should neither Create or Free it. You're just using it to refer to an existing dataset.

procedure TForm1.Button2Click(Sender: TObject);
var
  DS : TDataSet;
  UserNameField: TField;  // Minor change for efficiency
begin
  DS := GetDBGenericData(dbSOURCE, 'LIST_ALL_SCHEMAS', [] );

  // Call FieldByName only once; no need to create or
  // free this either.
  UserNameField := DS.FieldByName('USERNAME');

  while not DS.Eof do
  begin
    ShowMessage(UserNameField.AsString);
    DS.Next;
  end;

  // I'd probably remove the `Close` unless the function call
  // above specifically opened it before returning it.
  DS.Close;
end;