#1 2021-07-07 08:14:37

larand54
Member
Registered: 2018-12-25
Posts: 96

How to read from database feeding a filtered list without memory leak

How to read from database feeding a filtering list without memory leakage?

I have a windows-service that reads data from a table into a TObjectList
which is customized to filter out some data i.e. duplicate records.
That's because I couldn't find out how to do that with SQL and mORMot.
I have created a solution that works but I think it might be a
smarter solution.
Anyone that can tell?

Here is my solution:
Alt 1.

Alt 1. Just need one list and the finally is simpler.
procedure TEvNServer.readPkgPrefix(out aPrefixList: TPrefixList);
var
  SQL: RawUTF8;
  ppf: TSQLPkgPrefix;
  newPkgPrefix: TSQLPkgPrefix;
begin
  SQL := 'usedBySync = ? ORDER BY DefaultPrefix desc ';
  ppf := TSQLPkgPrefix.CreateAndFillPrepare(fDBServer, SQL, [1]);
  aPrefixList := TPrefixList.create;
  try
    while ppf.FillOne do begin
      newPkgPrefix := TSQLPkgPrefix.create;       // Clone object before adding to list
      newPkgPrefix.assign(ppf);                   //
      if aPrefixList.add(newPkgPrefix) = -1 then  // if object not accepted by the list,
        newPkgPrefix.free;                        // it must be free:d, otherwise mem-leakage
    end;
  finally
    ppf.free;  // must be free:d otherwise mem-leakage
  end;
end;

Alt 2.

Alt 2. Dont need to clone and add the assign method to TSQLPkgPrefix class.
procedure TEvNServer.readPkgPrefix(out aPrefixList: TPrefixList);
var
  SQL: RawUTF8;
  ppf: TSQLPkgPrefix;
  tmpList: TObjectList<TSQLPkgPrefix>;
begin
  SQL := 'usedBySync = ? ORDER BY DefaultPrefix desc ';
  tmpList := fDBServer.RetrieveList<TSQLPkgPrefix>(SQL, [1], '');
  aPrefixList := TPrefixList.create;
  try
    for ppf in tmpList do begin
      if aPrefixList.add(ppf) = -1 then begin
        ppf.free;
      end;
    end;
  finally
    if assigned(tmpList) then begin
      tmpList.OwnsObjects := false;
      freeAndNil(tmpList);
    end;
  end;
end;

Last edited by larand54 (2021-07-07 09:53:39)


Delphi-11, WIN10

Offline

#2 2021-07-07 10:08:30

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,258
Website

Re: How to read from database feeding a filtered list without memory leak

The FillOne version is faster since it will avoid some memory allocations.
So I am in favor of Alt 1.


Small optimization:

  SQL := 'usedBySync = ? ORDER BY DefaultPrefix desc ';
  aPrefixList := TPrefixList.create; // moved before to avoid a memory leak of ppf if the SQL is incorrect
  ppf := TSQLPkgPrefix.CreateAndFillPrepare(fDBServer, SQL, [1]);
  try
    newPkgPrefix := TSQLPkgPrefix.create;       
    while ppf.FillOne(newPkgPrefix) do 
      if aPrefixList.add(newPkgPrefix) >= 0 then  // if object accepted by the list,
        newPkgPrefix := TSQLPkgPrefix.create;    // it is owned by it -> need a new instance
    newPkgPrefix.Free;
  finally
    ppf.Free;
  end;

And I would not put aPrefixList as an "out" parameter, but as an input parameter, allocated by the caller - otherwise you may leak memory in case of exception.

Offline

#3 2021-07-07 13:57:05

larand54
Member
Registered: 2018-12-25
Posts: 96

Re: How to read from database feeding a filtered list without memory leak

Thanks, that was much better - I've already tested and it works perfectly! smile


Delphi-11, WIN10

Offline

Board footer

Powered by FluxBB