Domanda

Questa domanda si riferisce a questo commento di Ikegami:

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

in questo filo.

Cosa guadagno se imposto RaiseError A 0 in tali situazioni?

#!/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: $@" };

Produzione:

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.
È stato utile?

Soluzione

Se falliscono per qualche motivo, la maggior parte dei metodi $dbh:

  • (Se RaiseError l'opzione è impostata su 0) ritorno undef
  • (Se RaiseError l'opzione è impostata su 1) esce immediatamente dallo script ("die") con il motivo dell'errore fornito come messaggio di uscita.

Il punto chiave qui è che spetta a te come elaborare gli errori.Se lo desideri, puoi semplicemente ignorarli, ad esempio (il seguente ovviamente funzionerà con RaiseError impostato 0 soltanto):

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

In questo frammento (copiato dalla risposta di @ikegami che hai menzionato nella tua domanda) scorri un elenco di impostazioni per la connessione DB;se qualche connessione ti dà un undef, ne scegli semplicemente un altro e non fai nulla con l'errore.

Di solito, però, devi fare qualcosa di più del semplice "successivo" quando si verifica un errore, ma anche in questo caso hai due scelte:o controlla ogni $dbh-istruzione correlata con qualcosa del genere:

$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');

(COME or le parti verranno eseguite solo se le corrispondenti "parti sinistre" restituiscono valore false in contesto booleano).

...o semplicemente racchiudi tutto questo nel blocco 'try-catch' di 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($@);
}

Cosa scegliere, dipende da te:è una decisione comune tra "errori nelle istruzioni di ritorno" (tranne che per recuperare un errore effettivo devi chiedere all'oggetto $dbh) e, beh, eccezioni.

Ma il punto è che non puoi scrivere solo questo:

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

...se hai impostato RaiseError A 0.In questo caso lo script non morirà, $sth verrà assegnato un undef, e ottieni un errore "derivativo" (poiché non puoi chiamare un metodo su undef).

Ed è esattamente quello che è successo nell'ultima parte del codice nella tua domanda originale.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top