Pergunta

Esta questão refere-se a este comentário de Ikegami:

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

nisso fio.

O que eu ganho se eu definir RaiseError para 0 em tais situações?

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

Saída:

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.
Foi útil?

Solução

Se falhar por algum motivo, a maioria dos métodos $dbh irá:

  • (se RaiseError a opção está definida como 0) retornar undef
  • (se RaiseError a opção está definida como 1) sair imediatamente do script ('die') com o motivo do erro fornecido como mensagem de saída.

O ponto principal aqui é que depende de você como processar os erros.Se desejar, você pode simplesmente ignorá-los, por exemplo (o seguinte obviamente funcionará com RaiseError definido como 0 apenas):

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

Neste trecho (copiado da resposta de @ikegami que você mencionou em sua pergunta), você percorre uma lista de configurações para conexão de banco de dados;se alguma conexão lhe der uma undef, você simplesmente vai para outro e não faz nada com erro.

Normalmente, porém, você precisa fazer mais do que apenas 'próximo' quando ocorre um erro - mas, novamente, você tem duas opções:ou verifique cada $dbhdeclaração relacionada com algo assim:

$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 partes serão executadas somente se suas 'partes esquerdas' correspondentes forem avaliadas como false no contexto booleano).

... ou apenas coloque tudo isso no bloco 'try-catch' do 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($@);
}

O que escolher, depende de você:é uma decisão comum entre 'erros nas instruções de retorno' (exceto que para buscar um erro real você precisa perguntar ao objeto $dbh) e, bem, exceções.

Mas o resultado final é que você não pode escrever apenas isto:

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

...se você definiu RaiseError para 0.Neste caso, o script não morrerá, $sth será atribuído um undef, e você recebe um erro 'derivado' (já que você não pode chamar um método em undef).

E foi exatamente isso que aconteceu na última parte do código da sua pergunta original.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top