Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Firebird e Interbase (https://www.clubdelphi.com/foros/forumdisplay.php?f=19)
-   -   Capturar una excepcion en Delphi producida por FIREBIRD (https://www.clubdelphi.com/foros/showthread.php?t=14380)

ronson 18-09-2004 11:38:42

Capturar una excepcion en Delphi producida por FIREBIRD
 
Hola amigos, en primer lugar saludaros despues de una larga inactvidad de algun mes debido a un proyecto realmente grande en LOTUS DOMINO, pero ya estoy aqui para dar follón a la gran NURIA, o a los dioses KINOBI y CADETILL.

Mi pregunta es la siguiente, me creo una excepcion en FIREBIRD que se dispara en un trigger. Como puedo darle formato a en el codigo DELPHI, de manera que me salga una ventanita dieciendome el Texto de la expecion generada en FIRECBIRD. Ahora solo me sale lo siguiente:

Código:

exception 1.
NO HAY SUFICIENTES PRODUCTOS EN EL ALMACEN.

De antemando muchisimas gracias a todos.

Sinaloense 18-09-2004 19:04:28

try
//codigo
except
on E: Exception do ErrorDialog(E.Message, E.HelpContext);
end;

ozegarra 01-02-2008 22:35:26

Aprovecho este hilo para hacer una consulta sobre excepciones FireBird.

Yo genero mis excepciones en FireBird y las ejecuto segun alguna condicion en un Procedure(firebird tambien).

El tema es que yo quiero capturar ese mensaje de la excepcion por delphi. Estoy usando adoquery para ejecutar mis Procedures.

Si alguien pudiera asesorarme le agradeceria mucho ya que quiza para muchos es algo sencillo pero yo recien empiezo con el Delphi y sigo aprendiendo cosas nuevas.

Saludos
Oscar

PepeLolo 03-02-2008 18:56:49

Hola,

El código indicado por "Sinaloense" es el que necesitas para controlar las excepciones de la BBDD.

un saludo

ozegarra 15-02-2008 23:04:34

uy, despues de tiempo. Estuve en otras y recien retomo el tema. Probe con la sentencia descrita pero sale un error que dice :
Código Delphi [-]
Undeclared identifier: 'ErrorDialog'

Nuevamente gracias por la atencion.

Oscar

RolphyReyes 16-02-2008 21:02:10

Saludos.

Oscar, ErrorDialog es un nombre que le dio Sinaloense por decir un nombre a un metodo que llame un Showmessage o MessageDlg.

En cuanto a capturar la excepcion la gente de FibPlus tienen un tremendo componente para esto, es de pago vale la pena tener estos componentes.

Hasta luego.

Lepe 17-02-2008 14:42:52

No hace falta comprar nada.

Pon un ApplicationsEvents en tu ventana principal. En el evento OnException, puedes programar lo que quieras. Dentro del evento haz un showmessage de E.Message

Ahora en tus rutinas tienes 3 opciones mutuamente excluyentes:

1.- No poner bloques try..excepts, de forma que al ocurrir una excepción, ésta llegue al componente ApplicationsEvents.OnException en el que has programado lo que quieras hacer.

2.- Usar bloques try ... excepts, pero permitir que dicha excepción se lance de nuevo.

Típico caso, en la rutina haces un rollback de la transacción y después en el Application.OnException muestras el mensaje al usuario:
Código Delphi [-]
procedure mirutina;
begin 

  try 
     trans.StartTransaction;
      qryRestarStocks.ExecQuery; // suponemos que eso hace lanzar una excepción en la base de datos
     trans.Commit;
  except
  begin
     trans.Rollback; // anulamos los cambios hechos;
     raise; // re-lanzamos la misma excepción para que llegue al Application.OnException
  end;

3.- Usamos bloques try ... except, pero nos comemos la excepción. No llegará al Application.OnException. No se mostrará ningún mensaje al usuario.
Código Delphi [-]
procedure mirutina;
begin 

  try 
     trans.StartTransaction;
      qryRestarStocks.ExecQuery; // suponemos que eso hace lanzar una excepción en la base de datos
     trans.Commit;
  except
  begin
     trans.Rollback; // anulamos los cambios hechos;
     // raise; Aquí la gran diferencia.
  end;

Saludos

Lepe 17-02-2008 14:45:37

Cita:

Empezado por RolphyReyes (Mensaje 266420)
Saludos.

Oscar, ErrorDialog es un nombre que le dio Sinaloense por decir un nombre a un metodo que llame un Showmessage o MessageDlg.

Pues yo creo que no, ese dialogo existe en Delphi y si no me equivoco tienes que añadir un "uses" determinado. Busca en la ayuda.

Saludos

RolphyReyes 17-02-2008 15:59:01

Saludos.

Lepe en mi ayuda no existe ningun topico sobre ese metodo, pero si en la tuya existe entonces favor de poner la explicación.

Gracias.

Lepe 17-02-2008 18:34:33

Vaya, tienes razón, se ve que me he confundido con DatabaseError de la unidad DB, el uso es parecido.

Saludos

ozegarra 18-02-2008 15:27:01

Gracias muchachos por la ayuda.
Estuve intentando con el aplicationEvents y capturar el mensaje en el evento onExepcion pero no entra a ese evento. Derrepente estoy mostrando mal el mensaje desde firebird. Muestro un ejm. de codigo de mi procedimiento a ver si me pueden ayudar un pokito mas:
Código SQL [-]
if (Contador=0) then
   begin
   exception No_hay_Stock;
   /*suspend;*/
   end

y en delphi ejecutado el procedimiento asi:
Código Delphi [-]
ADOQuery_ActLocales.Active:=False;
    ADOQuery_ActLocales.Parameters.ParamByName('Accion').Value := Accion;
    ADOQuery_ActLocales.Parameters.ParamByName('Item').Value := EdtCodigo.Text);
    ADOQuery_ActLocales.Parameters.ParamByName('Cantidad').Value := EdtCantidad.Text;
    ADOQuery_ActLocales.ExecSQL;


Espero haber sido lo suficiente claro y me puedan ayudar.
Muchas gracias.


Oscar

Lepe 18-02-2008 16:18:58

Conceptualmente, está mal:

Código Delphi [-]
ADOQuery_ActLocales.Parameters.ParamByName('Cantidad').Value := EdtCantidad.Text;

Si el campo cantidad está definido como un integer en la base de datos, debes hacer la conversión:
Código Delphi [-]
ADOQuery_ActLocales.Parameters.ParamByName('Cantidad').Value := StrToInt(EdtCantidad.Text);

Al usar Variants, hay que tener cuidado en esos tipos de detalles, que después internamente el Variant puede hacer lo que no esperas.

Saludos

ozegarra 18-02-2008 16:25:26

ese solo era un ejm. ahi no esta mi problema, mi problema es al querer capturar la excepcion de delphi.

Gracias de todas maneras por la buena intencion.

Saludos
Oscar

Lepe 18-02-2008 16:50:55

Entonces crea un SP vacío, que solo incluya la llamada a una excepción (así te olvidas de los datos que le pasas al SP y de lo que haga internamente).

Un botón ejecuta ese SP.

El ApplicationsEvents, debe tener algún código escrito, porque de lo contrario el optimizador del compilador eliminará la referencia.

El concepto es simple:
Si no tienes un ApplicationsEvents, la excepción se muestra en pantalla.
Si tienes un ApplicationsEvents.OnException, la excepción primero pasa por dicho evento, después se muestra en pantalla.

Código Delphi [-]
procedure TSXXXX.AplicationException(...E:Exception;....);
begin
   ShowMessage('Mi mensaje personal ' + E.Message);
end;


Saludos

lbuelvas 20-02-2008 22:50:50

Hola foro,

Para atrapar errores utilizo una rutina (no me acuerdo de donde tome unas porciones de código y lo mejore) que me ha servido tanto para firebird 1.5 como para interbase 6.0.2.0.

Esto funciona con los componentes IBX y atrapa los errores mas comunes y los pone en español.

En una biblioteca crear los siguientes procedimientos:

Código Delphi [-]
//Manejo de Errores EDataBaseError (Nivel aplicacion) y EIBError (Nivel Interbase)
procedure  _errores_interbase  (E: EDatabaseError; var Action: TDataAction);
procedure  _errores_database   (E: EDatabaseError);

//*************************************************************************
//Manejo de Errores EDataBaseError (Nivel aplicacion) y EIBError (Nivel Interbase)
//*************************************************************************

//atrapa el error generado por el motor de bases de Datos Interbase V.6.01 o posterior
//E              -> es el nombre de la excepcion tipo EDatabaseError
//Action         -> la accion que debe tomar el Dataset
procedure _errores_interbase (E: EDatabaseError; var Action: TDataAction);
Var
 Nro_Error : Variant;
 cadena: string;
begin
  cadena := E.Message;
  _errores_database(E);
  if (E is EIBError) then begin
    SysUtils.Beep;
    Nro_Error :=  (E as EIBError).IBErrorCode;
    case (E as EIBError).IBErrorCode of
      //isc_unique_key_violation             335544665L violation of PRIMARY or UNIQUE KEY constraint
      335544665: begin
                   E.Create('El identificador para la tabla ya se ha utilizado.');
                   MessageDlg(E.Message,mtWarning,[mbOK],0);
                 end;
      //isc_not_valid                        335544347L validation error for column
      335544347: begin  //Valor NULL o diferente al dominio
                   //validation error for column XXXX, value "*** null ***"'
                   E.Create('Error de Validacion, valor requerido para el campo ' +
                             Copy(E.Message, 28, Pos(',',E.Message) - 28));
                   MessageDlg(E.Message,mtWarning,[mbOK],0);
                 end;
     //isc_foreign_key                       335544466L violation of FOREIGN KEY constraint
      335544466: begin
                   E.Create('Se ha violado la restriccion: '                                                        + _fin_linea(1) +
                             Copy(E.Message,Pos('"',E.Message), Length(E.Message) - Pos('"',E.Message)  )    + '".' + _fin_linea(1) +
                            'El registro actual tiene asociado(s) registro(s) en otra tabla que dependen de él, ó'  + _fin_linea(1) +
                            'se esta colocando un valor inválido en un campo del registro actual');
                   E.Message := StringReplace(E.Message, 'on table', 'de la tabla', [rfreplaceall]);
                   MessageDlg(E.Message,mtWarning,[mbOK],0);
                 end;
      //isc_dsql_error                       335544569L Dynamic SQL Error
      335544569: begin
                   E.Create('Error de Conversión de la Cadena : ' +
                   Copy(E.Message,Pos('"',E.Message), Length(E.Message) - Pos('"',E.Message)  ) );
                   MessageDlg(E.Message,mtWarning,[mbOK],0);
                 end;
      //isc_except                           335544517L exception 
      335544517: begin
                   E.Create('Excepcion : ' +
                   Copy(E.Message,Pos(_fin_linea(1) , E.Message), Length(E.Message)));
                   MessageDlg(E.Message,mtWarning,[mbOK],0);
                 end;
      else         MessageDlg('Error (' + IntToStr(Nro_Error) + ') - ' + E.Message,mtWarning,[mbOK],0);
    end;  //case
  end;// If EIBError
  Action := daAbort;
end;

//atrapa el error generado por la aplicacion
//E              -> es el nombre de la excepcion tipo EDatabaseError
procedure _errores_database (E: EDatabaseError);
var
  cadena: string;
  posicion: integer;
  longitud: integer;
begin
  if (E is EDatabaseError) then begin
    SysUtils.Beep;
    cadena := E.Message;
    if pos('must have a value',cadena) <> 0 then begin
      posicion := pos(chr(39),cadena);
      delete(cadena,1,posicion);
      posicion := pos(chr(39),cadena);
      longitud := length(cadena);
      delete(cadena,posicion,longitud);
      MessageDlg('El campo' + _comillas(cadena) + 'debe tener un valor',mtWarning, [mbOK],0);
    end;
  end;
end;

En los datamodulos o donde tenga los componentes de conexion a bases de datos colocar, en mi caso se llama DataModulo.

Código Delphi [-]
procedure Maneja_Error   (DataSet: TDataSet; E: EDatabaseError; var Action: TDataAction);

procedure TDataModulo.Maneja_Error(DataSet: TDataSet; E: EDatabaseError; var Action: TDataAction);
begin
  _errores_interbase(E,Action);
end;

y en los eventos OnPostError y OnDeleteError de los TIBDataset escriba directamente

Código Delphi [-]
Maneja_Error

peccatum 26-02-2008 21:21:24

Cita:

Empezado por Lepe (Mensaje 266480)

2.- Usar bloques try ... excepts, pero permitir que dicha excepción se lance de nuevo.

Hola,

Yo he elegido este método, el problema que tengo es que antes de mostrar el mensaje de la excepción al usuario la ejecución de mi programa se corta siendo necesario darle F9 devuelta para que recién ahí se muestre el mensaje y queden los objetos en el estado que yo quiero... ¿hay algúna forma de que esto no ocurra?

este es el código que produce la excepción:

Código Delphi [-]
try                 
                MDOTransaction1.StartTransaction;                 
                MDODataset1.QInsert.params.ByName('CANTI').AScurrency := 1;
                MDODataset1.QInsert.Params.ByName('NUMERO_CONTRATO').asInteger := Ncontrato;
                MDODataSet1.QInsert.Params.ByName('CATEGORIA').ASString :=   RXDBGrid1.Fields[1].AsString;
                MDODataSet1.Qinsert.Params.ByName('TARIFA').ASsTring := RXDBGrid1.Fields[0].AsString;
                MDODataSet1.QInsert.Params.ByName('PRECIO_UNITARIO').asCurrency := RXDBGRID1.Fields[4].ASCurrency;
                MDOQuery1.Close;
                IF stt[1] = 'K'  THEN                 MDOQuery1.SQL.Strings[14] := 'and tarifas.tipo <> '+ quotedStr('KM');
                if stt[1] = 'C' then                 MDOQuery1.SQL.Strings[15] := 'and tarifas.tipo <> '+ quotedStr('Combustible');
                MDOdataset1.QInsert.ExecQuery;
                MDOdataset1.open;
                MDOquery1.open;
               except                   
                        MDOTransaction1.Rollback;                   
                        MDOdataset1.Open;                                   
                        MDOquery1.Open;                    
                        raise;
               end;

'MDOdataset1.QInsert.ExecQuery ' es la linea que produce la excepción, como dije antes se corta la ejecución y me da un mensaje de el componente y me disgusta que eso ocurra quiero que solo se notifique el mensaje de error al usuario....


Gracias

Lepe 26-02-2008 22:02:31

Lanza tu ejecutable desde el Explorador de windows, no verás ese aviso ;).

PD: Si quieres puedes deshabilitar ese mensaje de Delphi, en Tools -> Debugger Options -> "Stop on Exception" (o algo así se llama ;)).

Saludos

maeyanes 26-02-2008 22:03:36

Hola...

Lo que te sucede solo es cuando estás ejecutando la aplicación desde el debugger...

Trata ejecutando tu aplicación desde afuera y verás que trabaja como debe ser...



Saludos...

peccatum 12-03-2008 02:40:18

Gracias Lepe y maeyanes ya configuré el debugger para que no moleste en las pruebas.

Tengo otra inquietud y necesito opiniones al respecto, el escenario es masomenos el siguiente:

Un form1 en el cual dispongo de una rejilla, barra de navegación, campos de búsqueda y los elementos no visuales necesarios (Dataset para consulta y actualizaciones, Datasources, Etcétera).

Programé para lograr que cuando el usuario apreta el botón de la barra navegadora para realizar una inserción (+) se abra ótro form2 en donde aparecen todos los campos de edicion y botones para que el usuario cargue datos para luego darle al botón 'aceptar' con lo cual se intenta guardar lo ingresado. Los campos en el form2 apúntan al dataset en el form1. En el botón 'Aceptar' es que tengo una estructúra del tipo try...except, en donde intento realizar el post del dataset en el form1. El problema aparece cuando ocurre una excepción al intentar guardar los datos: se muestra el mensaje de la excepción e inmediatamente se cierra el form 2 dejando el form 1 'on top'. El comportamiento que yo quiero es que al ocurrir una excepción se muestre el mensaje del error pero que no se cierre el formulario y el usuario pueda seguir trabajando con los datos que había intentado guardar...

Se entiende? qué sería lo más recomendable en esta situación?

de antemano muchas gracias!

Saludos...

Dens 31-08-2010 21:57:19

Amigos disculpenme la ignorancia pero es que no veo por ningun lado applicationevents :(, suponiendo que es un componente.


La franja horaria es GMT +2. Ahora son las 11:22:02.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi