Uncaught exceptions

Discussion of open issues, suggestions and bugs regarding MyDAC (Data Access Components for MySQL) for Delphi, C++Builder, Lazarus (and FPC)
Post Reply
gosta100
Posts: 9
Joined: Tue 29 Nov 2011 16:35

Uncaught exceptions

Post by gosta100 » Fri 21 Dec 2012 22:39

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.

gosta100
Posts: 9
Joined: Tue 29 Nov 2011 16:35

Re: Uncaught exceptions

Post by gosta100 » Sat 22 Dec 2012 12:13

I am sorry, I posted this under the wrong category, can some moderator erase this?

AndreyZ

Re: Uncaught exceptions

Post by AndreyZ » Mon 24 Dec 2012 09:43

Hello,

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;
, and the 'test' message occurs when MySQL server is unavailable. Please modify this code to demonstrate the problem.

gosta100
Posts: 9
Joined: Tue 29 Nov 2011 16:35

Re: Uncaught exceptions

Post by gosta100 » Fri 04 Jan 2013 16:23

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

gosta100
Posts: 9
Joined: Tue 29 Nov 2011 16:35

Re: Uncaught exceptions

Post by gosta100 » Fri 04 Jan 2013 21:05

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

AndreyZ

Re: Uncaught exceptions

Post by AndreyZ » Tue 08 Jan 2013 15:09

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:

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;
, and there were no problems with exception handling. Please modify this code to demonstrate the problem.

gosta100
Posts: 9
Joined: Tue 29 Nov 2011 16:35

Re: Uncaught exceptions

Post by gosta100 » Tue 08 Jan 2013 21:18

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:

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.
MyDACTestApp3.lpi:

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>
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?

AndreyZ

Re: Uncaught exceptions

Post by AndreyZ » Wed 09 Jan 2013 13:32

Please try using the following code:

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;
Can you catch the EDivByZero error with it? If no, please consult with Lazarus developers.

gosta100
Posts: 9
Joined: Tue 29 Nov 2011 16:35

Re: Uncaught exceptions

Post by gosta100 » Wed 09 Jan 2013 15:10

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?

scarre
Posts: 4
Joined: Wed 09 Jan 2013 15:27

Re: Uncaught exceptions

Post by scarre » Wed 09 Jan 2013 15:49

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 ?

AndreyZ

Re: Uncaught exceptions

Post by AndreyZ » Thu 10 Jan 2013 13:23

Thank you for the information. We have fixed this problem. This fix will be included in the next MyDAC build.

Post Reply