There is a bug in the AnyDAC/FireDAC DA driver that under certain conditions results in a EADException exception with the following message when a connections is acquired:
[FireDAC][Stan][Def]-254. Definition [__DACD_1] is not found in […\AnyDAC\DB\ADConnectionDefs.ini]
I found the bug while working on a server application that uses AnyDAC under the hood for scheduled background processes. The exception occurs because the TDAEAnyDACDriver.LookupConnectionString driver method fails to verify that an AD connection definition added by a previous call to LookupConnectionString method still exists in ADManager. The previously added connection definition can be lost, for example, if ADManager is closed/opened by other code using AnyDAC.
The fix for the problem is to modify the LookupConnectionString method. Below is the code change I made to workaround the issue:
function TDAEAnyDACDriver.LookupConnectionString(const AConnectionString: String;
AParsedParams: TStringList): String;
var
i: Integer;
ic: IADStanConnectionDef;
cn: string;
begin
i := FConnectionDefs.IndexOf(AConnectionString);
// Start new code
if i <> -1 then begin
cn:= Format('__DACD_%d', [Integer(FConnectionDefs.Objects[i])]);
if (ADManager.FindConnection(cn) = nil) then begin
FConnectionDefs.Delete(i);
i:= -1;
end;
end;
// End new code
if i = -1 then begin
Inc(FConnectionDefIndex);
FConnectionDefs.AddObject(AConnectionString, TObject(FConnectionDefIndex));
ic:= ADManager.ConnectionDefs.AddConnectionDef;
ic.Name := Format('__DACD_%d', [FConnectionDefIndex]);
ic.Params.AddStrings(AParsedParams);
Result := ic.Name;
end
else
Result := Format('__DACD_%d', [Integer(FConnectionDefs.Objects[i])]);
end;
Here is an updated version of my patch that has been tested in production. I fixed a coding error and added logic to conditionally reset FConnectionDefIndex to zero. Allowing FConnectionDefIndex to continue to increment in theory could be a problem if it happened a couple of billion times
One additional concern I have is that there appears to be a race condition if multiple connections are being created at the same time. There is no synchronization in the driver to prevent multiple threads from reading/updating FConnectionDefs and FConnectionDefIndex simultaneously. There may be a locking mechanism elsewhere in RODA to prevent reentrancy, but I am not familiar enough with the code to know where to look.
function TDAEAnyDACDriver.LookupConnectionString(const AConnectionString: String;
AParsedParams: TStringList): String;
var
i: Integer;
ic: IADStanConnectionDef;
cn: string;
begin
i := FConnectionDefs.IndexOf(AConnectionString);
// Start new code
if i <> -1 then begin
cn:= Format('__DACD_%d', [Integer(FConnectionDefs.Objects[i])]);
if (ADManager.ConnectionDefs.FindConnectionDef(cn) = nil) then begin
FConnectionDefs.Delete(i);
if (FConnectionDefs.Count = 0) then
FConnectionDefIndex := 0;
i:= -1;
end;
end;
// End new code
if i = -1 then begin
Inc(FConnectionDefIndex);
FConnectionDefs.AddObject(AConnectionString, TObject(FConnectionDefIndex));
ic:= ADManager.ConnectionDefs.AddConnectionDef;
ic.Name := Format('__DACD_%d', [FConnectionDefIndex]);
ic.Params.AddStrings(AParsedParams);
Result := ic.Name;
end
else
Result := Format('__DACD_%d', [Integer(FConnectionDefs.Objects[i])]);
end;
Do you know if this issue is fixed? I looked through the notes for the Spring 2014 release and did not see any reference to this issue. I have not looked at the source for the Spring 2014 release since I could not risk installing the new version and breaking my development environment.
Please let me know the status of this bug and whether it will be fixed in the next release. This is a critical issue since it breaks all of our production RemObjects applications that use AnyDAC/FireDAC. We are using the patch I provided and it is working without issue in heavy production use.