Pregunta

Esta pregunta se refiere a este comentario de Ikegami:

[...] But if you're going to put an eval around every statement, just use RaiseError => 0. [...]

en esto hilo.

¿Qué gano si me pongo RaiseError a 0 en tales situaciones?

#!/usr/bin/env perl
use warnings;
use 5.10.1;
use DBI;

my $db = 'my_test_sqlite_db.sqlite';
open my $fh, '>', $db or die $!;
close $fh or die $!;

my ( $dbh, $sth );
eval {
    $dbh = DBI->connect( "DBI:SQLite:dbname=$db", "", "", {} );
};
if ( $@ ) { print $@ };

my $table = 'my_sqlite_table';

say   "RaiseError = 1";
say   "PrintError = 0";
$dbh->{RaiseError} = 1;
$dbh->{PrintError} = 0;
eval {
    $sth = $dbh->prepare( "SELECT * FROM $table" );
    $sth->execute();
};
if ( $@ ) { print "ERROR: $@" };

say "\nRaiseError = 0";
say   "PrintError = 1";
$dbh->{RaiseError} = 0;
$dbh->{PrintError} = 1;
eval {
    $sth = $dbh->prepare( "SELECT * FROM $table" );
    $sth->execute();
};
if ( $@ ) { print "ERROR: $@" };

say "\nRaiseError = 0";
say   "PrintError = 0";
$dbh->{RaiseError} = 0;
$dbh->{PrintError} = 0;
eval {
    $sth = $dbh->prepare( "SELECT * FROM $table" );
    $sth->execute();
};
if ( $@ ) { print "ERROR: $@" };

Producción:

RaiseError = 1
PrintError = 0
ERROR: DBD::SQLite::db prepare failed: no such table: my_sqlite_table at ./perl2.pl line 23.

RaiseError = 0
PrintError = 1
DBD::SQLite::db prepare failed: no such table: my_sqlite_table at ./perl2.pl line 33.
ERROR: Can't call method "execute" on an undefined value at ./perl2.pl line 34.

RaiseError = 0
PrintError = 0
ERROR: Can't call method "execute" on an undefined value at ./perl2.pl line 44.
¿Fue útil?

Solución

Si falla por alguna razón, la mayoría de los métodos $dbh harán lo siguiente:

  • (si RaiseError la opción está establecida en 0) regresar undef
  • (si RaiseError La opción está configurada en 1) salir inmediatamente del script ("morir") con el motivo del error indicado como mensaje de salida.

El punto clave aquí es que depende de usted cómo procesar los errores.Si lo desea, puede simplemente ignorarlos, por ejemplo (lo siguiente obviamente funcionará con RaiseError ajustado a 0 solo):

for my $db ( ... ) {
    my $dbh = get_database_handle( $db )
       or next;
    ...
}

En este fragmento (copiado de la respuesta de @ikegami que mencionaste en tu pregunta), recorre una lista de configuraciones para la conexión de base de datos;si alguna conexión te da una undef, simplemente busca otro y no hace nada con el error.

Sin embargo, normalmente tienes que hacer algo más que simplemente "siguiente" cuando ocurre un error, pero, de nuevo, tienes dos opciones:ya sea cheque cada $dbh-declaración relacionada con algo como esto:

$sth = $dbh->prepare('some_params') 
  or process_db_error('In prepare');
...
$res = $sth->execute('another_set_of_params') 
  or process_db_error('In execute');
...
$res->doAnythingElse('something completely different') 
  or process_db_error('In something completely different');

(como or Las partes se ejecutarán sólo si sus correspondientes 'partes izquierdas' se evalúan como false en contexto booleano).

...o simplemente envuelva todo esto en el bloque 'try-catch' de Perlish:

if (!eval {    
   $sth = $dbh->prepare('some_params');
   ...
   $res = $sth->execute('another_set_of_params');
   ...
   $res->doSomethingElse('something completely different') 
   ...
   1  # No exception
}) {
   process_db_error($@);
}

Qué elegir, tú decides:es una decisión común entre 'errores en declaraciones de devolución' (excepto que para recuperar un error real hay que preguntar al objeto $dbh) y, bueno, excepciones.

Pero la conclusión es que no puedes escribir solo esto:

$sth = $dbh->do_something('that_can_result_in_error');
$sth->do_something('else');

...si lo estableciste RaiseError a 0.En este caso, el guión no morirá. $sth se le asignará un undef, y obtienes un error 'derivado' (ya que no puedes llamar a un método en undef).

Y eso es exactamente lo que sucedió en la última parte del código de su pregunta original.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top