1

I have a stored procedure that is called from a before update trigger. In this procedure I check for some condition, if met an exception is thrown

The problem the exception display many data I don't want to show to the user:

exception 4
Exception_Name
Error message At procedure 'proc_name' line: 3, col: 50
At trigger 'trigger_name' line: 8, col: 17.

Is there a way to display only the message ? if not is there a way to stop the update without thrown an exception?

I'm using Firebird 2.5.1 With Delphi 2010 DB connection: IBDac and update is triggered from post method

Arioch 'The
  • 15,799
  • 35
  • 62
zac
  • 4,495
  • 15
  • 62
  • 127
  • 1
    This is more a Delphi question than a Firebird one. You should include some info on how you perform the update from Delphi and the components you use to connect to the database. – jachguate Mar 26 '13 at 02:43
  • 1
    In the our FB-based application (with Oracle was almost same): Catch exception; Analise it, get localized message, throw exception with text like real_ex_message || '##' || human_ex_message; Parse ex message in the client app and show only part after '##'. – Abelisto Mar 26 '13 at 03:17
  • @jachguate info included now – zac Mar 26 '13 at 03:20
  • @Abelisto Thanks yes that is a solution for the problem – zac Mar 26 '13 at 03:21

2 Answers2

1

A bit late answer but better later than never.

Here is my solution. Not too nice or professional, kind of hacking, but I haven't found any better option.

I have modified the following procedure in the IB.pas file (IBX), works fine. I know the OP using different package to access the database, but I guess the logic will be the same.

procedure IBDataBaseError;
var
  sqlcode: Long;
  IBErrorCode: Long;
  local_buffer: array[0..IBHugeLocalBufferLength - 1] of char;
  usr_msg: string;
  status_vector: PISC_STATUS;
  IBDataBaseErrorMessages: TIBDataBaseErrorMessages;
  AStrList: TStringList;
  i: integer;
begin
  usr_msg := '';

  { Get a local reference to the status vector.
    Get a local copy of the IBDataBaseErrorMessages options.
    Get the SQL error code }
  status_vector := StatusVector;
  IBErrorCode := StatusVectorArray[1];
  IBDataBaseErrorMessages := GetIBDataBaseErrorMessages;
  sqlcode := GetGDSLibrary.isc_sqlcode(status_vector);

  if (ShowSQLCode in IBDataBaseErrorMessages) then
    usr_msg := usr_msg + 'SQLCODE: ' + IntToStr(sqlcode); {do not localize}
  Exclude(IBDataBaseErrorMessages, ShowSQLMessage);
  if (ShowSQLMessage in IBDataBaseErrorMessages) then
  begin
    GetGDSLibrary.isc_sql_interprete(sqlcode, local_buffer, IBLocalBufferLength);
    if (ShowSQLCode in IBDataBaseErrorMessages) then
      usr_msg := usr_msg + CRLF;
    usr_msg := usr_msg + string(local_buffer);
  end;

  if (ShowIBMessage in IBDataBaseErrorMessages) then
  begin
// unnecessary code
//    if (ShowSQLCode in IBDataBaseErrorMessages) or
//       (ShowSQLMessage in IBDataBaseErrorMessages) then
//      usr_msg := usr_msg + CRLF;
    while (GetGDSLibrary.isc_interprete(local_buffer, @status_vector) > 0) do
    begin
      if (usr_msg <> '') and (usr_msg[Length(usr_msg)] <> LF) then
        usr_msg := usr_msg + CRLF;
      usr_msg := usr_msg + string(local_buffer);
    end;

    // then next condition is optional, remove if you use other 
    // initialization than SetIBDataBaseErrorMessages([ShowIBMessage])
    if (IBDataBaseErrorMessages = [ShowIBMessage]) then
    begin
      AStrList:= TStringList.Create;
      try
        AStrList.Text:= usr_msg;
        // apply to user defined exception only
        if (AStrList.Count > 0) and (Pos('exception', AStrList[0]) = 1) then
          // i'm using ! on the end of every exception
          // if you don't, just simply keep the 3. line (AStrList[2])
          // of AStrList and delete the rest of lines 
          for i:= AStrList.Count - 1 downto 0 do
            if (Pos('!', AStrList[i]) = 0) then
              AStrList.Delete(i);
        usr_msg:= AStrList.Text;
      finally
        AStrList.Free;
      end;
    end;
  end;

  while (usr_msg <> '') and ((usr_msg[Length(usr_msg)] = '.') or (usr_msg[Length(usr_msg)] = LF) or (usr_msg[Length(usr_msg)] = CR)) do
    Delete(usr_msg, Length(usr_msg), 1);
  MonitorHook.SendError(IntToStr(sqlcode) + ' ' + IntToStr(IBErrorCode) + ' ' + usr_msg);
  if sqlcode <> -551 then
    raise EIBInterBaseError.Create(sqlcode, IBErrorCode, usr_msg)
  else
    raise EIBInterBaseRoleError.Create(sqlcode, IBErrorCode, usr_msg)
end;
tcxbalage
  • 696
  • 1
  • 10
  • 30
0

The exception most likely has properties for each of the parts of the error. You might look at the declaration of the exception class (which you didn't bother to provide in your question). For instance, EDatabaseError has properties for ErrorCode and ErrorMessage; I'd suspect that the FireBird error has them as well.

This means that your exception handler could do something like this:

try
  .. some database thing
except
  on E: EFireBirdException do
    ShowMessage(E.ErrorMessage);
end;

Note that I have no idea what the FireBird exception classes provide; I'm just providing the type of thing you should be looking for in the Firebird exception class declaration. Other useful values usually are ErrorCode.

Again, to see what's available to use is in the exception class declaration and the specific features of the exception class (like E.Message, E.Code, and so forth you'll need to see the specific class you're dealing with.

Ken White
  • 123,280
  • 14
  • 225
  • 444
  • dont speculate too much I dont know what information to include !! – zac Mar 26 '13 at 03:18
  • @Welliam Unfortunately there's no `ibdac` tag to get the attention of some expert in that connection layer. If you have the sources available, you can learn there the properties of the raised exception. You can also fire code completion to inspect what the exception object gives you. – jachguate Mar 26 '13 at 04:06
  • 1
    @jachguate he can always get experts advice at http://forums.devart.com/viewforum.php?f=24 IBDAC is UniDAC's subset – Arioch 'The Mar 26 '13 at 07:54
  • 1
    @Welliam you can start with reporting exception class and the declaration of that class – Arioch 'The Mar 26 '13 at 07:54
  • @Arioch you're right, I'm regular devart user for dbExpress drivers but I don't know the UniDAC products. Devart support is very good, so Welliam should ask there. – jachguate Mar 26 '13 at 12:55