Skip to content

IBoldDatabase has no way to release the connection from CreateAnotherDatabaseConnection; DbCopy and the DB validator leak the wrapper #92

Description

@bero

IBoldDatabase.CreateAnotherDatabaseConnection hands out a new connection wrapper, but the interface has no matching way to dispose of it. The wrappers are TBoldNonRefCountedObjects, so the two adapter-neutral callers leak one wrapper per extra connection:

  • TBoldDbCopy.ProcessTables (Source/Persistence/DB/BoldDbCopy.pas) creates a source and a destination wrapper per worker, releases their queries and Closes them in the finally - and lets the locals go out of scope.
  • TBoldDbValidatorThread.Execute (Source/PMapper/Validator/BoldDbValidator.pas) creates one per validator thread and ends with fBoldDatabase := nil.

Found while fixing #90 and #91 (the UniDAC wrapper's own leaks). With those fixed, freeing the wrapper would now clean up its cached queries and its owned DAC connection - but nothing frees it.

Root cause

The callers cannot free what they hold: IBoldDatabase.Implementor is the DAC component (TFDConnection / TUniConnection), not the wrapper, and casting to TBoldFireDACConnection or TBoldUniDACConnection - what the FireDAC unit test does - is not available to adapter-neutral code. Every other resource of the interface comes as a pair (GetQuery/ReleaseQuery, GetExecQuery/ReleaseExecQuery, GetTable/ReleaseTable); CreateAnotherDatabaseConnection has no Release... counterpart.

Fix

  • IBoldDatabase.ReleaseAnotherDatabaseConnection(var ADatabase: IBoldDatabase), implemented once in TBoldDatabaseWrapper (every adapter's connection class descends from it): obtain the wrapper object from the interface (as TObject), nil the reference, free the object. The reference is nilled before the free because the wrapper is not reference counted but assigning nil still calls _Release.
  • TBoldDbCopy.ProcessTables: release both wrappers in the finally.
  • TBoldDbValidatorThread.Execute: release the wrapper instead of dropping the reference.
  • The FireDAC and UniDAC tests that dispose an extra connection use the new method instead of a class cast.

Files changed

  • Source/Persistence/DB/BoldDBInterfaces.pas
  • Source/Persistence/DB/BoldDbCopy.pas
  • Source/PMapper/Validator/BoldDbValidator.pas
  • UnitTest/Code/Persistence/Test.PersistenceFireDAC.pas, UnitTest/Code/Persistence/UniDAC/Test.PersistenceUniDAC.pas

Testing

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions