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; procedure SynCompletionProposal1Execute(Kind: SynCompletionType;
Sender: TObject; var CurrentInput: WideString; var x, y: Integer; Sender: TObject; var CurrentInput: WideString; var x, y: Integer;
var CanExecute: Boolean); var CanExecute: Boolean);
procedure PerformConnect;
procedure pcChange(Sender: TObject); procedure pcChange(Sender: TObject);
procedure ValidateControls(FrmIsFocussed: Boolean = true); procedure ValidateControls(FrmIsFocussed: Boolean = true);
procedure ValidateQueryControls(FrmIsFocussed: Boolean = true); procedure ValidateQueryControls(FrmIsFocussed: Boolean = true);
@ -1507,6 +1506,7 @@ var
DefaultLastrunDate : String; DefaultLastrunDate : String;
frm : TfrmUpdateCheck; frm : TfrmUpdateCheck;
dlgResult: Integer; dlgResult: Integer;
AutoReconnect: Boolean;
begin begin
// Do an updatecheck if checked in settings // Do an updatecheck if checked in settings
if GetRegValue(REGNAME_DO_UPDATECHECK, DEFAULT_DO_UPDATECHECK) then begin if GetRegValue(REGNAME_DO_UPDATECHECK, DEFAULT_DO_UPDATECHECK) then begin
@ -1602,8 +1602,21 @@ begin
end else end else
Exit; Exit;
end else begin 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: // Cannot be done in OnCreate because we need ready forms here:
dlgResult := ConnectionWindow(Self); dlgResult := ConnectionWindow(Self);
// Re-enable AutoReconnect in Registry!
if AutoReconnect then begin
OpenRegistry;
MainReg.WriteBool( REGNAME_AUTORECONNECT, true );
end;
if dlgResult = mrCancel then begin if dlgResult = mrCancel then begin
Close; Close;
Exit; Exit;
@ -1617,11 +1630,40 @@ procedure TMainForm.DoAfterConnect;
var var
i: Integer; i: Integer;
lastUsedDB: WideString; lastUsedDB: WideString;
v: String[50];
v1, v2, v3: String;
rx: TRegExpr;
begin begin
// Activate logging // Activate logging
if GetRegValue(REGNAME_LOGTOFILE, DEFAULT_LOGTOFILE) then if GetRegValue(REGNAME_LOGTOFILE, DEFAULT_LOGTOFILE) then
ActivateFileLogging; 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); DatabasesWanted := explode(';', FConn.DatabaseList);
if FConn.DatabaseListSort then if FConn.DatabaseListSort then
DatabasesWanted.Sort; DatabasesWanted.Sort;
@ -1676,9 +1718,6 @@ begin
if DataGridHasChanges then if DataGridHasChanges then
actDataPostChangesExecute(Self); actDataPostChangesExecute(Self);
if prefLogToFile then
DeactivateFileLogging;
// Clear database and table lists // Clear database and table lists
DBtree.ClearSelection; DBtree.ClearSelection;
DBtree.FocusedNode := nil; DBtree.FocusedNode := nil;
@ -1699,6 +1738,10 @@ begin
FMysqlConn.Disconnect; FMysqlConn.Disconnect;
FreeAndNil(FMysqlConn); FreeAndNil(FMysqlConn);
end; end;
if prefLogToFile then
DeactivateFileLogging;
SetWindowConnected( false ); SetWindowConnected( false );
SetWindowName( main.discname ); SetWindowName( main.discname );
Application.Title := APPNAME; Application.Title := APPNAME;
@ -2386,7 +2429,6 @@ begin
parCompress := IntToStr(Integer(GetRegValue(REGNAME_COMPRESSED, DEFAULT_COMPRESSED, Session))); parCompress := IntToStr(Integer(GetRegValue(REGNAME_COMPRESSED, DEFAULT_COMPRESSED, Session)));
parDatabase := Utf8Decode(GetRegValue(REGNAME_ONLYDBS, '', Session)); parDatabase := Utf8Decode(GetRegValue(REGNAME_ONLYDBS, '', Session));
parSortDatabases := IntToStr(Integer(GetRegValue(REGNAME_ONLYDBSSORTED, DEFAULT_ONLYDBSSORTED, Session))); parSortDatabases := IntToStr(Integer(GetRegValue(REGNAME_ONLYDBSSORTED, DEFAULT_ONLYDBSSORTED, Session)));
DoDisconnect;
if InitConnection(parHost, parPort, parUser, parPass, parDatabase, parTimeout, parCompress, parSortDatabases) then begin if InitConnection(parHost, parPort, parUser, parPass, parDatabase, parTimeout, parCompress, parSortDatabases) then begin
SessionName := Session; SessionName := Session;
DoAfterConnect; DoAfterConnect;
@ -2400,73 +2442,46 @@ end;
} }
function TMainform.InitConnection(parHost, parPort, parUser, parPass, parDatabase, parTimeout, parCompress, parSortDatabases: WideString): Boolean; function TMainform.InitConnection(parHost, parPort, parUser, parPass, parDatabase, parTimeout, parCompress, parSortDatabases: WideString): Boolean;
var var
AutoReconnect: Boolean; MysqlConnection: TMysqlConn;
Profile: TOpenConnProf;
begin begin
// fill structure // fill structure
ZeroMemory (@FConn,SizeOf(FConn)); ZeroMemory(@Profile, SizeOf(Profile));
Profile.MysqlParams.Protocol := 'mysql';
with FConn do Profile.MysqlParams.Host := Trim( parHost );
begin Profile.MysqlParams.Port := StrToIntDef(parPort, DEFAULT_PORT);
MysqlParams.Protocol := 'mysql'; Profile.MysqlParams.Database := '';
MysqlParams.Host := Trim( parHost ); Profile.MysqlParams.User := parUser;
MysqlParams.Port := StrToIntDef(parPort, DEFAULT_PORT); Profile.MysqlParams.Pass := parPass;
MysqlParams.Database := '';
MysqlParams.User := parUser;
MysqlParams.Pass := parPass;
// additional
if Integer(parCompress) > 0 then if Integer(parCompress) > 0 then
MysqlParams.PrpCompress := 'true' Profile.MysqlParams.PrpCompress := 'true'
else else
MysqlParams.PrpCompress := 'false'; 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));
MysqlParams.PrpTimeout := parTimeout; MysqlConnection := TMysqlConn.Create(@Profile);
MysqlParams.PrpDbless := 'true';
MysqlParams.PrpClientLocalFiles := 'true';
MysqlParams.PrpClientInteractive := 'true';
DatabaseList := parDatabase;
DatabaseListSort := Boolean(StrToIntDef(parSortDatabases, 0));
end;
FMysqlConn := TMysqlConn.Create(@FConn);
// attempt to establish connection // 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 // 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; Result := False;
FreeAndNil (FMysqlConn); FreeAndNil(MysqlConnection);
Exit; end else begin
end;
Result := True; Result := True;
Profile.MysqlConn := MysqlConnection.Connection;
FConn.MysqlConn := FMysqlConn.Connection; // use this connection (instead of zConn) if Assigned(FMysqlConn) then
DoDisconnect;
// Temporarily disable AutoReconnect in Registry // Assign global connection objects
// in case of unexpected application-termination FConn := Profile;
AutoReconnect := GetRegValue(REGNAME_AUTORECONNECT, DEFAULT_AUTORECONNECT); FMysqlConn := MysqlConnection;
if AutoReconnect then begin
OpenRegistry;
MainReg.WriteBool( REGNAME_AUTORECONNECT, False );
end; 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 ); ShowStatus( STATUS_MSG_READY );
end; end;
@ -3185,49 +3200,6 @@ begin
end; 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; function TMainForm.GetQueryRunning: Boolean;
begin begin
Result := ( QueryRunningInterlock = 1 ); Result := ( QueryRunningInterlock = 1 );
@ -5933,18 +5905,10 @@ begin
TimerConnectedTimer(self); TimerConnectedTimer(self);
TimerHostUptime.Enabled := false; TimerHostUptime.Enabled := false;
TimerHostUptimeTimer(self); 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; FQueryRunning := false;
try try
FMysqlConn.Connection.Reconnect; FMysqlConn.Connection.Reconnect;
PerformConnect; time_connected := 0;
finally finally
FQueryRunning := true; FQueryRunning := true;
end; end;