Avoid unusable main form after failed session connect. Keep the old connection alive until it is verified that the new one is available. Moves code out of PerformConnect to DoAfterConnect.

Todo: Fix reconnection logic, see bug #858
This commit is contained in:
Ansgar Becker
2009-01-04 21:59:36 +00:00
parent 58c034ded8
commit e6cb169193

View File

@ -563,7 +563,6 @@ type
procedure SynCompletionProposal1Execute(Kind: SynCompletionType;
Sender: TObject; var CurrentInput: WideString; var x, y: Integer;
var CanExecute: Boolean);
procedure PerformConnect;
procedure pcChange(Sender: TObject);
procedure ValidateControls(FrmIsFocussed: Boolean = true);
procedure ValidateQueryControls(FrmIsFocussed: Boolean = true);
@ -1507,6 +1506,7 @@ var
DefaultLastrunDate : String;
frm : TfrmUpdateCheck;
dlgResult: Integer;
AutoReconnect: Boolean;
begin
// Do an updatecheck if checked in settings
if GetRegValue(REGNAME_DO_UPDATECHECK, DEFAULT_DO_UPDATECHECK) then begin
@ -1602,8 +1602,21 @@ begin
end else
Exit;
end else begin
// Temporarily disable AutoReconnect in Registry
// in case of unexpected application-termination
OpenRegistry;
AutoReconnect := GetRegValue(REGNAME_AUTORECONNECT, DEFAULT_AUTORECONNECT);
if AutoReconnect then begin
OpenRegistry;
MainReg.WriteBool( REGNAME_AUTORECONNECT, False );
end;
// Cannot be done in OnCreate because we need ready forms here:
dlgResult := ConnectionWindow(Self);
// Re-enable AutoReconnect in Registry!
if AutoReconnect then begin
OpenRegistry;
MainReg.WriteBool( REGNAME_AUTORECONNECT, true );
end;
if dlgResult = mrCancel then begin
Close;
Exit;
@ -1617,11 +1630,40 @@ procedure TMainForm.DoAfterConnect;
var
i: Integer;
lastUsedDB: WideString;
v: String[50];
v1, v2, v3: String;
rx: TRegExpr;
begin
// Activate logging
if GetRegValue(REGNAME_LOGTOFILE, DEFAULT_LOGTOFILE) then
ActivateFileLogging;
time_connected := 0;
TimerConnected.Enabled := true;
LogSQL( 'Connection established with host "' + FMysqlConn.Connection.hostname +
'" on port ' + IntToStr(FMysqlConn.Connection.Port) );
LogSQL( 'Connection-ID: ' + IntToStr( MySQLConn.Connection.GetThreadId ) );
// Detect server version
// Be careful with version suffixes, for example: '4.0.31-20070605_Debian-5-log'
v := GetVar( 'SELECT VERSION()' );
rx := TRegExpr.Create;
rx.ModifierG := True;
rx.Expression := '^(\d+)\.(\d+)\.(\d+)';
if rx.Exec(v) then begin
v1 := rx.Match[1];
v2 := rx.Match[2];
v3 := rx.Match[3];
end;
rx.Free;
mysql_version := MakeInt(v1) *10000 + MakeInt(v2) *100 + MakeInt(v3);
tabHost.Caption := 'Host: '+MySQLConn.Connection.HostName;
showstatus('MySQL '+v1+'.'+v2+'.'+v3, 3);
// On Re-Connection, try to restore lost properties
if FMysqlConn.Connection.Database <> '' then
ExecUseQuery( FMysqlConn.Connection.Database );
DatabasesWanted := explode(';', FConn.DatabaseList);
if FConn.DatabaseListSort then
DatabasesWanted.Sort;
@ -1676,9 +1718,6 @@ begin
if DataGridHasChanges then
actDataPostChangesExecute(Self);
if prefLogToFile then
DeactivateFileLogging;
// Clear database and table lists
DBtree.ClearSelection;
DBtree.FocusedNode := nil;
@ -1699,6 +1738,10 @@ begin
FMysqlConn.Disconnect;
FreeAndNil(FMysqlConn);
end;
if prefLogToFile then
DeactivateFileLogging;
SetWindowConnected( false );
SetWindowName( main.discname );
Application.Title := APPNAME;
@ -2386,7 +2429,6 @@ begin
parCompress := IntToStr(Integer(GetRegValue(REGNAME_COMPRESSED, DEFAULT_COMPRESSED, Session)));
parDatabase := Utf8Decode(GetRegValue(REGNAME_ONLYDBS, '', Session));
parSortDatabases := IntToStr(Integer(GetRegValue(REGNAME_ONLYDBSSORTED, DEFAULT_ONLYDBSSORTED, Session)));
DoDisconnect;
if InitConnection(parHost, parPort, parUser, parPass, parDatabase, parTimeout, parCompress, parSortDatabases) then begin
SessionName := Session;
DoAfterConnect;
@ -2400,73 +2442,46 @@ end;
}
function TMainform.InitConnection(parHost, parPort, parUser, parPass, parDatabase, parTimeout, parCompress, parSortDatabases: WideString): Boolean;
var
AutoReconnect: Boolean;
MysqlConnection: TMysqlConn;
Profile: TOpenConnProf;
begin
// fill structure
ZeroMemory (@FConn,SizeOf(FConn));
ZeroMemory(@Profile, SizeOf(Profile));
Profile.MysqlParams.Protocol := 'mysql';
Profile.MysqlParams.Host := Trim( parHost );
Profile.MysqlParams.Port := StrToIntDef(parPort, DEFAULT_PORT);
Profile.MysqlParams.Database := '';
Profile.MysqlParams.User := parUser;
Profile.MysqlParams.Pass := parPass;
if Integer(parCompress) > 0 then
Profile.MysqlParams.PrpCompress := 'true'
else
Profile.MysqlParams.PrpCompress := 'false';
Profile.MysqlParams.PrpTimeout := parTimeout;
Profile.MysqlParams.PrpDbless := 'true';
Profile.MysqlParams.PrpClientLocalFiles := 'true';
Profile.MysqlParams.PrpClientInteractive := 'true';
Profile.DatabaseList := parDatabase;
Profile.DatabaseListSort := Boolean(StrToIntDef(parSortDatabases, 0));
with FConn do
begin
MysqlParams.Protocol := 'mysql';
MysqlParams.Host := Trim( parHost );
MysqlParams.Port := StrToIntDef(parPort, DEFAULT_PORT);
MysqlParams.Database := '';
MysqlParams.User := parUser;
MysqlParams.Pass := parPass;
// additional
if Integer(parCompress) > 0 then
MysqlParams.PrpCompress := 'true'
else
MysqlParams.PrpCompress := 'false';
MysqlParams.PrpTimeout := parTimeout;
MysqlParams.PrpDbless := 'true';
MysqlParams.PrpClientLocalFiles := 'true';
MysqlParams.PrpClientInteractive := 'true';
DatabaseList := parDatabase;
DatabaseListSort := Boolean(StrToIntDef(parSortDatabases, 0));
end;
FMysqlConn := TMysqlConn.Create(@FConn);
MysqlConnection := TMysqlConn.Create(@Profile);
// attempt to establish connection
if FMysqlConn.Connect <> MCR_SUCCESS then begin
Showstatus( 'Connecting to ' + Profile.MysqlParams.Host + '...' );
if MysqlConnection.Connect <> MCR_SUCCESS then begin
// attempt failed -- show error
MessageDlg ( 'Could not establish connection! Details:'+CRLF+CRLF+FMysqlConn.LastError, mtError, [mbOK], 0);
MessageDlg ( 'Could not establish connection! Details:'+CRLF+CRLF+MysqlConnection.LastError, mtError, [mbOK], 0);
Result := False;
FreeAndNil (FMysqlConn);
Exit;
FreeAndNil(MysqlConnection);
end else begin
Result := True;
Profile.MysqlConn := MysqlConnection.Connection;
if Assigned(FMysqlConn) then
DoDisconnect;
// Assign global connection objects
FConn := Profile;
FMysqlConn := MysqlConnection;
end;
Result := True;
FConn.MysqlConn := FMysqlConn.Connection; // use this connection (instead of zConn)
// Temporarily disable AutoReconnect in Registry
// in case of unexpected application-termination
AutoReconnect := GetRegValue(REGNAME_AUTORECONNECT, DEFAULT_AUTORECONNECT);
if AutoReconnect then begin
OpenRegistry;
MainReg.WriteBool( REGNAME_AUTORECONNECT, False );
end;
Showstatus( 'Connecting to ' + FConn.MysqlParams.Host + '...' );
try
PerformConnect();
except
TimerConnectErrorCloseWindow.Enabled := true;
Exit;
end;
// Re-enable AutoReconnect in Registry!
if AutoReconnect then begin
OpenRegistry;
MainReg.WriteBool( REGNAME_AUTORECONNECT, true );
end;
ShowStatus( STATUS_MSG_READY );
end;
@ -3185,49 +3200,6 @@ begin
end;
procedure TMainForm.PerformConnect;
var
v : String[50];
v1, v2, v3 : String;
rx : TRegExpr;
begin
try
time_connected := 0;
TimerConnected.Enabled := true;
LogSQL( 'Connection established with host "' + FMysqlConn.Connection.hostname +
'" on port ' + IntToStr(FMysqlConn.Connection.Port) );
LogSQL( 'Connection-ID: ' + IntToStr( MySQLConn.Connection.GetThreadId ) );
// Detect server version
// Be careful with version suffixes, for example: '4.0.31-20070605_Debian-5-log'
v := GetVar( 'SELECT VERSION()' );
rx := TRegExpr.Create;
rx.ModifierG := True;
rx.Expression := '^(\d+)\.(\d+)\.(\d+)';
if rx.Exec(v) then begin
v1 := rx.Match[1];
v2 := rx.Match[2];
v3 := rx.Match[3];
end;
rx.Free;
mysql_version := MakeInt(v1) *10000 + MakeInt(v2) *100 + MakeInt(v3);
tabHost.Caption := 'Host: '+MySQLConn.Connection.HostName;
showstatus('MySQL '+v1+'.'+v2+'.'+v3, 3);
// On Re-Connection, try to restore lost properties
if FMysqlConn.Connection.Database <> '' then
ExecUseQuery( FMysqlConn.Connection.Database );
except
on E: Exception do begin
LogSQL( E.Message, true );
Screen.Cursor := crDefault;
MessageDlg( E.Message, mtError, [mbOK], 0 );
raise;
end;
end;
end;
function TMainForm.GetQueryRunning: Boolean;
begin
Result := ( QueryRunningInterlock = 1 );
@ -5933,18 +5905,10 @@ begin
TimerConnectedTimer(self);
TimerHostUptime.Enabled := false;
TimerHostUptimeTimer(self);
// 1) CheckConnection is always called from
// within an FQueryRunning-enabled block.
// 2) PerformConnect (see below) will make calls
// that open an FQueryRunning block, causing an
// error message.
//
// Therefore, flick the state of the running
// flag before running PerformConnect().
FQueryRunning := false;
try
FMysqlConn.Connection.Reconnect;
PerformConnect;
time_connected := 0;
finally
FQueryRunning := true;
end;