* fcl-db: Oracle connection: don't leak resources client side and server side on failed connection. Patch by Al Popov. Thank you very much. Solves issue #26868

git-svn-id: trunk@28833 -
This commit is contained in:
reiniero 2014-10-16 12:40:23 +00:00
parent 123b9f789a
commit d69d25432a

View File

@ -384,11 +384,10 @@ begin
end; end;
procedure TOracleConnection.DoInternalConnect; procedure TOracleConnection.DoInternalConnect;
var var
ConnectString : string; ConnectString : string;
TempServiceContext : POCISvcCtx; TempServiceContext : POCISvcCtx;
IsConnected : boolean;
begin begin
{$IfDef LinkDynamically} {$IfDef LinkDynamically}
InitialiseOCI; InitialiseOCI;
@ -397,42 +396,78 @@ begin
inherited DoInternalConnect; inherited DoInternalConnect;
//todo: get rid of FUserMem, as it isn't used //todo: get rid of FUserMem, as it isn't used
FUserMem := nil; FUserMem := nil;
IsConnected := false;
// Create environment handle try
if OCIEnvCreate(FOciEnvironment,oci_default,nil,nil,nil,nil,0,FUserMem) <> OCI_SUCCESS then // Create environment handle
DatabaseError(SErrEnvCreateFailed,self); if OCIEnvCreate(FOciEnvironment,OCI_DEFAULT,nil,nil,nil,nil,0,FUserMem) <> OCI_SUCCESS then
// Create error handle DatabaseError(SErrEnvCreateFailed,self);
if OciHandleAlloc(FOciEnvironment,FOciError,OCI_HTYPE_ERROR,0,FUserMem) <> OCI_SUCCESS then // Create error handle
DatabaseError(SErrHandleAllocFailed,self); if OciHandleAlloc(FOciEnvironment,FOciError,OCI_HTYPE_ERROR,0,FUserMem) <> OCI_SUCCESS then
// Create Server handle DatabaseError(SErrHandleAllocFailed,self);
if OciHandleAlloc(FOciEnvironment,FOciServer,OCI_HTYPE_SERVER,0,FUserMem) <> OCI_SUCCESS then // Create server handle
DatabaseError(SErrHandleAllocFailed,self); if OciHandleAlloc(FOciEnvironment,FOciServer,OCI_HTYPE_SERVER,0,FUserMem) <> OCI_SUCCESS then
// Initialize Server handle DatabaseError(SErrHandleAllocFailed,self);
if hostname='' then connectstring := databasename
else connectstring := '//'+hostname+'/'+databasename;
if OCIServerAttach(FOciServer,FOciError,@(ConnectString[1]),Length(ConnectString),OCI_DEFAULT) <> OCI_SUCCESS then
HandleError();
// Create temporary service-context handle for user authentication // Initialize server handle
if OciHandleAlloc(FOciEnvironment,TempServiceContext,OCI_HTYPE_SVCCTX,0,FUserMem) <> OCI_SUCCESS then if hostname='' then
DatabaseError(SErrHandleAllocFailed,self); connectstring := databasename
else
connectstring := '//'+hostname+'/'+databasename;
if OCIServerAttach(FOciServer,FOciError,@(ConnectString[1]),Length(ConnectString),OCI_DEFAULT) <> OCI_SUCCESS then
HandleError();
// Create user-session handle try
if OciHandleAlloc(FOciEnvironment,FOciUserSession,OCI_HTYPE_SESSION,0,FUserMem) <> OCI_SUCCESS then // Create temporary service-context handle for user authentication
DatabaseError(SErrHandleAllocFailed,self); if OciHandleAlloc(FOciEnvironment,TempServiceContext,OCI_HTYPE_SVCCTX,0,FUserMem) <> OCI_SUCCESS then
// Set the server-handle in the service-context handle DatabaseError(SErrHandleAllocFailed,self);
if OCIAttrSet(TempServiceContext,OCI_HTYPE_SVCCTX,FOciServer,0,OCI_ATTR_SERVER,FOciError) <> OCI_SUCCESS then
HandleError(); try
// Set username and password in the user-session handle // Create user-session handle
if OCIAttrSet(FOciUserSession,OCI_HTYPE_SESSION,@(Self.UserName[1]),Length(Self.UserName),OCI_ATTR_USERNAME,FOciError) <> OCI_SUCCESS then if OciHandleAlloc(FOciEnvironment,FOciUserSession,OCI_HTYPE_SESSION,0,FUserMem) <> OCI_SUCCESS then
HandleError(); DatabaseError(SErrHandleAllocFailed,self);
if OCIAttrSet(FOciUserSession,OCI_HTYPE_SESSION,@(Self.Password[1]),Length(Self.Password),OCI_ATTR_PASSWORD,FOciError) <> OCI_SUCCESS then try
HandleError(); // Set the server-handle in the service-context handle
// Authenticate if OCIAttrSet(TempServiceContext,OCI_HTYPE_SVCCTX,FOciServer,0,OCI_ATTR_SERVER,FOciError) <> OCI_SUCCESS then
if OCISessionBegin(TempServiceContext,FOciError,FOcIUserSession,OCI_CRED_RDBMS,OCI_DEFAULT) <> OCI_SUCCESS then HandleError();
HandleError(); // Set username and password in the user-session handle
// Free temporary service-context handle if OCIAttrSet(FOciUserSession,OCI_HTYPE_SESSION,@(Self.UserName[1]),Length(Self.UserName),OCI_ATTR_USERNAME,FOciError) <> OCI_SUCCESS then
OCIHandleFree(TempServiceContext,OCI_HTYPE_SVCCTX); HandleError();
if OCIAttrSet(FOciUserSession,OCI_HTYPE_SESSION,@(Self.Password[1]),Length(Self.Password),OCI_ATTR_PASSWORD,FOciError) <> OCI_SUCCESS then
HandleError();
// Authenticate
if OCISessionBegin(TempServiceContext,FOciError,FOcIUserSession,OCI_CRED_RDBMS,OCI_DEFAULT) <> OCI_SUCCESS then
HandleError();
IsConnected := true;
finally
if not IsConnected then
begin
OCIHandleFree(FOciUserSession,OCI_HTYPE_SESSION);
FOciUserSession := nil;
end;
end;
finally
// Free temporary service-context handle
OCIHandleFree(TempServiceContext,OCI_HTYPE_SVCCTX);
end;
finally
if not IsConnected then
OCIServerDetach(FOciServer,FOciError,OCI_DEFAULT);
end;
finally
if not IsConnected then
begin
if assigned(FOciServer) then
OCIHandleFree(FOciServer,OCI_HTYPE_SERVER);
if assigned(FOciError) then
OCIHandleFree(FOciError,OCI_HTYPE_ERROR);
if assigned(FOciEnvironment) then
OCIHandleFree(FOciEnvironment,OCI_HTYPE_ENV);
FOciEnvironment := nil;
FOciError := nil;
FOciServer := nil;
end;
end;
end; end;
procedure TOracleConnection.DoInternalDisconnect; procedure TOracleConnection.DoInternalDisconnect;
@ -441,36 +476,56 @@ var
begin begin
inherited DoInternalDisconnect; inherited DoInternalDisconnect;
// Create temporary service-context handle for user-disconnect if assigned(FOciEnvironment) then
if OciHandleAlloc(FOciEnvironment,TempServiceContext,OCI_HTYPE_SVCCTX,0,FUserMem) <> OCI_SUCCESS then begin
DatabaseError(SErrHandleAllocFailed,self); if assigned(FOciError) then
begin
if assigned(FOciServer) then
begin
if assigned(FOciUserSession) then
begin
try
// Create temporary service-context handle for user-disconnect
if OciHandleAlloc(FOciEnvironment,TempServiceContext,OCI_HTYPE_SVCCTX,0,FUserMem) <> OCI_SUCCESS then
DatabaseError(SErrHandleAllocFailed,self);
// Set the server handle in the service-context handle // Set the server handle in the service-context handle
if OCIAttrSet(TempServiceContext,OCI_HTYPE_SVCCTX,FOciServer,0,OCI_ATTR_SERVER,FOciError) <> OCI_SUCCESS then if OCIAttrSet(TempServiceContext,OCI_HTYPE_SVCCTX,FOciServer,0,OCI_ATTR_SERVER,FOciError) <> OCI_SUCCESS then
HandleError(); HandleError();
// Set the user session handle in the service-context handle // Set the user session handle in the service-context handle
if OCIAttrSet(TempServiceContext,OCI_HTYPE_SVCCTX,FOciUserSession,0,OCI_ATTR_SESSION,FOciError) <> OCI_SUCCESS then if OCIAttrSet(TempServiceContext,OCI_HTYPE_SVCCTX,FOciUserSession,0,OCI_ATTR_SESSION,FOciError) <> OCI_SUCCESS then
HandleError(); HandleError();
// Disconnect uses-session handle // Disconnect uses-session handle
if OCISessionEnd(TempServiceContext,FOciError,FOcIUserSession,OCI_DEFAULT) <> OCI_SUCCESS then if OCISessionEnd(TempServiceContext,FOciError,FOcIUserSession,OCI_DEFAULT) <> OCI_SUCCESS then
HandleError(); HandleError();
// Free user-session handle finally
OCIHandleFree(FOciUserSession,OCI_HTYPE_SESSION); // Free user-session handle
// Free temporary service-context handle OCIHandleFree(FOciUserSession,OCI_HTYPE_SESSION);
OCIHandleFree(TempServiceContext,OCI_HTYPE_SVCCTX); // Free temporary service-context handle
OCIHandleFree(TempServiceContext,OCI_HTYPE_SVCCTX);
FOciUserSession := nil;
end;
end;
// Disconnect server handle try
if OCIServerDetach(FOciServer,FOciError,OCI_DEFAULT) <> OCI_SUCCESS then // Disconnect server handle
HandleError(); if OCIServerDetach(FOciServer,FOciError,OCI_DEFAULT) <> OCI_SUCCESS then
HandleError();
// Free connection handles finally
OCIHandleFree(FOciServer,OCI_HTYPE_SERVER); // Free connection handles
OCIHandleFree(FOciError,OCI_HTYPE_ERROR); OCIHandleFree(FOciServer,OCI_HTYPE_SERVER);
OCIHandleFree(FOciEnvironment,OCI_HTYPE_ENV); FOciServer := nil;
end;
end;
OCIHandleFree(FOciError,OCI_HTYPE_ERROR);
FOciError := nil;
end;
OCIHandleFree(FOciEnvironment,OCI_HTYPE_ENV);
FOciEnvironment := nil;
end;
{$IfDef LinkDynamically} {$IfDef LinkDynamically}
ReleaseOCI; ReleaseOCI;
{$EndIf} {$EndIf}
end; end;
function TOracleConnection.AllocateCursorHandle: TSQLCursor; function TOracleConnection.AllocateCursorHandle: TSQLCursor;