fcl-db Postgres: connection leak from empty transaction

Summary

If there are no queries executed within an explicit transaction, a postgres connection is not released.

As a result, the number of open connections increments until the PQ limit is reached and the server refuses to open any new connections and execute queries.

System Information

  • Operating system: Windows and Linux
  • Compiler version: trunk
  • Device: Computer

Steps to reproduce

Do TSQLTransaction.StartTransaction+TSQLTransaction.Commit without any queries to see the connection count increase.

Example Project

program PGConnectionTest;

uses SQLDB, PQConnection;

var
  C: TPQConnection;
  T: TSQLTransaction;
  Q: TSQLQuery;
  I: Integer;
begin
  C := TPQConnection.Create(nil);
  try
    C.HostName := 'localhost';
    C.UserName := 'postgres';
    C.Password := '???';
    C.DatabaseName := '???';
    C.Connected := True;
    T := TSQLTransaction.Create(C);
    C.Transaction := T;

    Q := TSQLQuery.Create(C);
    Q.SQL.Text := 'SELECT sum(numbackends) FROM pg_stat_database'; // get database connection count
    for I := 1 to 200 do
    begin
      T.StartTransaction;
      try
        // do nothing -> PG handle (connection) is not released !!!
        T.Commit;
      except
        T.Rollback;
      end;

      T.StartTransaction;
      try
        Q.SQLConnection := C;
        Q.Transaction := T;
        Q.Open;
        Writeln('Connection count: ', Q.Fields[0].AsInteger); // see connection count increase
        Q.Close;
        T.Commit;
      except
        T.Rollback;
      end;
    end;
  finally
    C.Free;
  end;
end.

What is the current bug behavior?

Postgres connection is created with every new TSQLTransaction.StartTransaction and is not released.

Place a breakpoint in procedure TPGHandle.Connect; to see that PQconnectdb() is called every time in StartTransaction;.

What is the expected (correct) behavior?

Only one connection should be created and released every time.

Assignee Loading
Time tracking Loading