Delphi: Reference vs Copy of TADoConnection variable assignment

539 views Asked by At

I am trying to understand how Delphi handles an assignment. I have a global connection that is called GlobalConn (TADoConnection)...

i have a function that makes a database call using the variable passed in:

function MakeDBCall( AConnection : TAdoConnection )
var LocalConn : TAdoConn;
begin
   LocalConn := TAdoConnection.Create(nil);
   try
       LocalConn := AConnection
       ///create the table and perform action using the LocalConn
   finally
       LocalConn.free;    
   end;
end;

A call would be made using MakeDbCall(GlobalConn);

  1. What actually happens when LocalConn := AConnection (inside the function)? Is the reference count increased or a new copy assigned to the local variable?

  2. Does freeing the LocalConn impact the GlobalConn?

  3. Ideally i presume that making a copy is better (faster) than taking the connection string and assigning to the local variable and opening... is this a correct presumption?

  4. Is this handled differently from Delphi 7 and XE7-Xe10?

thanks

1

There are 1 answers

1
Ken White On

Your code does not do what you think it does. I've put in some comments to try to explain exactly what's happening.

function MakeDBCall( AConnection : TAdoConnection )
var 
  LocalConn : TAdoConn;
begin
  // This creates a brand new ADO connection. 
  LocalConn := TAdoConnection.Create(nil);
  try
    // This line discards the connection you've just created, 
    // orphaning it (leaking the memory), and sets LocalConn
    // to point to the object passed in as AConnection.
    LocalConn := AConnection

    ///create the table and perform action using the LocalConn
  finally
    // This line frees AConnection, making your global variable invalid
    LocalConn.free;    
  end;
end;

So to deal with the questions you asked directly:

  1. What actually happens when LocalConn := AConnection (inside the function)? Is the reference count increased or a new copy assigned to the local variable?

None of the above.

The assignment discards the brand new connection you just created, leaking the memory that was allocated, and LocalConn becomes a new variable that points to AConnection, not a copy. TADOConnection is not an interface, and therefore is not subject to reference counting. No new copy is assigned - LocalConn is just another variable that points to the connection instance you passed in to the function.

  1. Does freeing the LocalConn impact the GlobalConn?

Yes. It frees AConnection, making any references to it invalid, presumably your global connection instance. (It does nothing to the local connection you created with TADOConnection.Create(nil); that memory is leaked, because you discarded the only reference to it that could be used to free it.

  1. Ideally i presume that making a copy is better (faster) than taking the connection string and assigning to the local variable and opening... is this a correct presumption?

It might be, if in fact you were making a copy, but you're not.

  1. Is this handled differently from Delphi 7 and XE7-Xe10?

No. What I pointed out above is the same for every version of Delphi from v1 onward when dealing with the VCL and Windows. (FMX on mobile changes some things, but it wouldn't change the fact that you're still freeing the global object in error.)

If TADOConnection actually implements the Assign method, you can use it. It's unclear from the documentation, however, whether it is implemented or not; the documentation links to TPersistent.Assign. You can check the source for the version of Delphi you're actually using (I don't have D2007 on this laptop) to see if it's implemented. If it is, you can use something like this:

LocalConn := TADOConnection.Create(nil);
try
  LocalConn.Assign(AConnection);
  // Use LocalConn
finally
  LocalConn.Free;  // Frees the local copy
end;