Uncaught exceptions
Uncaught exceptions
Hello,
I am using MyDAC 7.1.4 under Lazarus 0.9.30.2. When issuing TMyCommand.Execute and the MySQL server is unavailable at the same time, I get some kind of exception I cannot catch in my console application. That means that even if I wrap my code around a "try ... except" block, the program will exit without being able to handle the exception raised. I do not see the same behaviour in a graphical fpcunit test application, where I can see the exceptions and handle them in the code. Could you tell me how I can effectively catch the exception?
Thank you.
I am using MyDAC 7.1.4 under Lazarus 0.9.30.2. When issuing TMyCommand.Execute and the MySQL server is unavailable at the same time, I get some kind of exception I cannot catch in my console application. That means that even if I wrap my code around a "try ... except" block, the program will exit without being able to handle the exception raised. I do not see the same behaviour in a graphical fpcunit test application, where I can see the exceptions and handle them in the code. Could you tell me how I can effectively catch the exception?
Thank you.
Re: Uncaught exceptions
I am sorry, I posted this under the wrong category, can some moderator erase this?
Re: Uncaught exceptions
Hello,
I have used the following code:, and the 'test' message occurs when MySQL server is unavailable. Please modify this code to demonstrate the problem.
I have used the following code:
Code: Select all
procedure TForm1.Button1Click(Sender: TObject);
begin
try
MyCommand1.SQL.Text := 'insert into dept(deptno) values(10)';
MyCommand1.Execute;
except
ShowMessage('test');
end;
end;
Re: Uncaught exceptions
Hello,
The problem I am referring to does not occur in graphical applications. It happens in console applications though, where such exceptions cannot be caught. Could you try to reproduce it and recommend a solution?
Thank you,
Stathis
The problem I am referring to does not occur in graphical applications. It happens in console applications though, where such exceptions cannot be caught. Could you try to reproduce it and recommend a solution?
Thank you,
Stathis
Re: Uncaught exceptions
Hi again,
I can confirm that this also happens with the latest version of MyDAC (7.6.11), under Lazarus 1.0 and FPC 2.6.0, on Linux.
Specifically, I reproduced the issue several times in the following scenario:
- MySQL server is up and running and you can successfully connect with TMyConnection.Connect
- Shut down MySQL server
- Try to execute a command with TMyCommand.Execute
- The program crashes without giving the chance to catch any exception
Please note that this only happens in console applications and not gui applications. Any help appreciated.
Stathis
I can confirm that this also happens with the latest version of MyDAC (7.6.11), under Lazarus 1.0 and FPC 2.6.0, on Linux.
Specifically, I reproduced the issue several times in the following scenario:
- MySQL server is up and running and you can successfully connect with TMyConnection.Connect
- Shut down MySQL server
- Try to execute a command with TMyCommand.Execute
- The program crashes without giving the chance to catch any exception
Please note that this only happens in console applications and not gui applications. Any help appreciated.
Stathis
Re: Uncaught exceptions
I have checked this question in the following environment:
Linux Ubuntu
Lazarus 1.0.4
MyDAC 7.6.11
, and I have used the following code in the console application:, and there were no problems with exception handling. Please modify this code to demonstrate the problem.
Linux Ubuntu
Lazarus 1.0.4
MyDAC 7.6.11
, and I have used the following code in the console application:
Code: Select all
con := TMyConnection.Create(nil);
cmd := TMyCommand.Create(nil);
try
con.Server := 'server';
con.Port := 3306;
con.Username := 'username';
con.Password := 'password';
con.Database := 'database';
con.LoginPrompt := False;
con.Open;
WriteLn('con is opened');
cmd.Connection := con;
cmd.SQL.Text := 'some command';
WriteLn('waiting');
ReadLn; // this is where MySQL server is shut down
try
cmd.Execute;
WriteLn('cmd is executed');
except
WriteLn('exception is raised');
end;
finally
cmd.Free;
con.Free;
ReadLn;
end;
Re: Uncaught exceptions
Hello Andrey,
My setup is:
Linux Ubuntu 12.04 desktop 64-bit
Lazarus 1.0.2 with FPC 2.6.0
MyDAC 7.6.11
MySQL version (output of mysqld --version):
mysqld Ver 5.5.24-0ubuntu0.12.04.1 for debian-linux-gnu on x86_64 ((Ubuntu))
I am testing with the following code, in a simple FreePascal program (not even console application):
MyDACTestApp3.lpr:
MyDACTestApp3.lpi:
Note that I am testing against localhost using user root, maybe that is also relevant.
I am testing under the following scenario:
- I launch the application, when MySQL Server is up
- I stop MySQL server with: service mysql stop
- Press <Enter> in the console
- The application just exists without printing anything, e.g. "exception is raised "
The exit code, which I get with "echo $?" is 141, which is related to SIGPIPE. When I turn on debugging, I see that a EMySqlException is raised, but immediately after that I get a SIGPIPE, which makes the application to exit abruptly.
Could you investigate and inform me of the outcome?
My setup is:
Linux Ubuntu 12.04 desktop 64-bit
Lazarus 1.0.2 with FPC 2.6.0
MyDAC 7.6.11
MySQL version (output of mysqld --version):
mysqld Ver 5.5.24-0ubuntu0.12.04.1 for debian-linux-gnu on x86_64 ((Ubuntu))
I am testing with the following code, in a simple FreePascal program (not even console application):
MyDACTestApp3.lpr:
Code: Select all
program MyDACTestApp3;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
sysutils,
Classes,
MyAccess;
var
con: TMyConnection;
cmd: TMyCommand;
begin
con := TMyConnection.Create(nil);
cmd := TMyCommand.Create(nil);
try
con.Server := '127.0.0.1';
con.Port := 3306;
con.Username := 'root';
con.Password := 'password';
con.Database := 'mydac_tests';
con.LoginPrompt := False;
con.Open;
WriteLn('con is opened');
cmd.Connection := con;
cmd.SQL.Text := 'some command';
WriteLn('waiting');
ReadLn; // this is where MySQL server is shut down
try
cmd.Execute;
WriteLn('cmd is executed');
except
on E: Exception do
begin
WriteLn('exception is raised ');
WriteLn(E.ClassName + ': ' + E.Message);
end;
end;
finally
cmd.Free;
con.Free;
ReadLn;
end;
end.
Code: Select all
<?xml version="1.0"?>
<CONFIG>
<ProjectOptions>
<Version Value="9"/>
<General>
<Flags>
<MainUnitHasCreateFormStatements Value="False"/>
<MainUnitHasTitleStatement Value="False"/>
</Flags>
<SessionStorage Value="InProjectDir"/>
<MainUnit Value="0"/>
<Title Value="MyDACTestApp3"/>
<UseAppBundle Value="False"/>
<ResourceType Value="res"/>
</General>
<i18n>
<EnableI18N LFM="False"/>
</i18n>
<VersionInfo>
<StringTable ProductVersion=""/>
</VersionInfo>
<BuildModes Count="1">
<Item1 Name="Default" Default="True"/>
</BuildModes>
<PublishOptions>
<Version Value="2"/>
<IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
<ExcludeFileFilter Value="*.(bak|ppu|o|so);*~;backup"/>
</PublishOptions>
<RunParams>
<local>
<FormatVersion Value="1"/>
<LaunchingApplication PathPlusParams="/usr/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/>
</local>
</RunParams>
<Units Count="1">
<Unit0>
<Filename Value="MyDACTestApp3.lpr"/>
<IsPartOfProject Value="True"/>
<UnitName Value="MyDACTestApp3"/>
</Unit0>
</Units>
</ProjectOptions>
<CompilerOptions>
<Version Value="11"/>
<Target>
<Filename Value="MyDACTestApp3"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<OtherUnitFiles Value="../../MyDAC/Source"/>
<UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<Other>
<CompilerMessages>
<MsgFileName Value=""/>
</CompilerMessages>
<CompilerPath Value="$(CompPath)"/>
</Other>
</CompilerOptions>
<Debugging>
<Exceptions Count="3">
<Item1>
<Name Value="EAbort"/>
</Item1>
<Item2>
<Name Value="ECodetoolError"/>
</Item2>
<Item3>
<Name Value="EFOpenError"/>
</Item3>
</Exceptions>
</Debugging>
</CONFIG>
I am testing under the following scenario:
- I launch the application, when MySQL Server is up
- I stop MySQL server with: service mysql stop
- Press <Enter> in the console
- The application just exists without printing anything, e.g. "exception is raised "
The exit code, which I get with "echo $?" is 141, which is related to SIGPIPE. When I turn on debugging, I see that a EMySqlException is raised, but immediately after that I get a SIGPIPE, which makes the application to exit abruptly.
Could you investigate and inform me of the outcome?
Re: Uncaught exceptions
Please try using the following code:
Can you catch the EDivByZero error with it? If no, please consult with Lazarus developers.
Code: Select all
var
a,b: double;
begin
try
b := 1;
a := b / 0;
except
on E: Exception do
begin
WriteLn('exception is raised ');
WriteLn(E.ClassName + ': ' + E.Message);
end;
end;
end;
Re: Uncaught exceptions
Hello Andrey,
Of course the EDivByZero exception is caught in a console application, no problem with fpc.
We have investigated and tracked very deep in the MyDAC source code and we came to the conclusion that the error is generated at line 278 in CRVioTcp.pas:
Result := fpsend(s, @Buf, len, flags);
As a matter of fact, upon detection of lost connection in TMyCommand.Execute, the exception EmySqlException with message: "Lost connection to MySQL server during query" is raised appropriately, but then there is a call to Disconnect which will ultimately go to fpsend again at line 278 in CRVioTcp.pas. Since the socket is invalid, the SIGPIPE signal will be raised.
In console applications, SIGPIPE signals cause the application to exit immediately because they are not handled by the standard fpc RTL (http://web.archiveorange.com/archive/v/ ... vncSxNbiG1). In graphical applications, SIGPIPE signals are either ignored or handled gracefully.
We tried modifying line 278 in CRVioTcp.pas to:
Result := fpsend(s, @Buf, len, flags or MSG_NOSIGNAL);
This forces SIGPIPE signals to be ignored in socket calls.
It works both for a console and graphical application. Exception EmySqlException with message: "Lost connection to MySQL server during query" is then indeed raised and caught as expected.
Can you verify with your developers if that is a viable change that could be made permanent?
Of course the EDivByZero exception is caught in a console application, no problem with fpc.
We have investigated and tracked very deep in the MyDAC source code and we came to the conclusion that the error is generated at line 278 in CRVioTcp.pas:
Result := fpsend(s, @Buf, len, flags);
As a matter of fact, upon detection of lost connection in TMyCommand.Execute, the exception EmySqlException with message: "Lost connection to MySQL server during query" is raised appropriately, but then there is a call to Disconnect which will ultimately go to fpsend again at line 278 in CRVioTcp.pas. Since the socket is invalid, the SIGPIPE signal will be raised.
In console applications, SIGPIPE signals cause the application to exit immediately because they are not handled by the standard fpc RTL (http://web.archiveorange.com/archive/v/ ... vncSxNbiG1). In graphical applications, SIGPIPE signals are either ignored or handled gracefully.
We tried modifying line 278 in CRVioTcp.pas to:
Result := fpsend(s, @Buf, len, flags or MSG_NOSIGNAL);
This forces SIGPIPE signals to be ignored in socket calls.
It works both for a console and graphical application. Exception EmySqlException with message: "Lost connection to MySQL server during query" is then indeed raised and caught as expected.
Can you verify with your developers if that is a viable change that could be made permanent?
Re: Uncaught exceptions
Since SIGPIPE signal handling is unix/linux specific, most probably writing something like this would do the trick in freepascal:
{$IFDEF UNIX}
Result := fpsend(s, @Buf, len, flags or MSG_NOSIGNAL);
{$ELSE}
Result := fpsend(s, @Buf, len, flags);
{$ENDIF}
Possibly, the same needs to be done for fprecv().
Also note that MSG_NOSIGNAL is defined in BaseUnix, so that unit must be conditionally added to the uses clause.
Possibly, SIGPIPE handling is different in MacOS (see http://bugs.freepascal.org/view.php?id=9401). Has anyone experienced this behavior on a Mac with a console (server/daemon) application ?
{$IFDEF UNIX}
Result := fpsend(s, @Buf, len, flags or MSG_NOSIGNAL);
{$ELSE}
Result := fpsend(s, @Buf, len, flags);
{$ENDIF}
Possibly, the same needs to be done for fprecv().
Also note that MSG_NOSIGNAL is defined in BaseUnix, so that unit must be conditionally added to the uses clause.
Possibly, SIGPIPE handling is different in MacOS (see http://bugs.freepascal.org/view.php?id=9401). Has anyone experienced this behavior on a Mac with a console (server/daemon) application ?
Re: Uncaught exceptions
Thank you for the information. We have fixed this problem. This fix will be included in the next MyDAC build.