Come posso evitare che il programma si chiuda quando il DBI di Perl rileva un errore durante la preparazione di un'istruzione?

StackOverflow https://stackoverflow.com/questions/836827

  •  08-07-2019
  •  | 
  •  

Domanda

Sto realizzando uno script che passa attraverso una tabella che contiene tutti gli altri nomi di tabella nel database. Mentre analizza ogni riga, controlla se la tabella è vuota di

select count(*) cnt from $table_name 

Alcune tabelle non esistono più nello schema e se lo faccio

select count(*) 

direttamente nel prompt dei comandi, restituisce l'errore:

  

206: La tabella specificata (adm_rpt_rec) non è nel database.

Quando lo eseguo dall'interno di Perl, lo aggiunge all'inizio:

  

Preparazione DBD :: Informix :: db non riuscita: SQL: -

Come posso evitare che il programma si chiuda quando tenta di preparare questa istruzione SQL?

È stato utile?

Soluzione

Codice di lavoro - supponendo che tu abbia un database 'store'.

#!/bin/perl -w
use strict;
use DBI;
my $dbh = DBI->connect('dbi:Informix:stores','','',
                       {RaiseError=>0,PrintError=>1}) or die;
$dbh->do("create temp table tlist(tname varchar(128) not null) with no log");
$dbh->do("insert into tlist values('systables')");
$dbh->do("insert into tlist values('syzygy')");

my $sth = $dbh->prepare("select tname from tlist");
$sth->execute;
while (my($tabname) =  $sth->fetchrow_array)
{
    my $sql = "select count(*) cnt from $tabname";
    my $st2 = $dbh->prepare($sql);
    if ($st2)
    {
        $st2->execute;
        if (my($num) = $st2->fetchrow_array)
        {
            print "$tabname: $num\n";
        }
        else
        {
            print "$tabname: error - missing?\n";
        }
    }
}
$sth->finish;
$dbh->disconnect;
print "Done - finished under control.\n";

Output dall'esecuzione del codice sopra.

systables: 72
DBD::Informix::db prepare failed: SQL: -206: The specified table (syzygy) is not in the database.
ISAM: -111: ISAM error:  no record found. at xx.pl line 14.
Done - finished under control.

Questo ha stampato l'errore ( PrintError = > 1 ), ma è continuato. Modificare 1 su 0 e non viene visualizzato alcun errore. Le parentesi nelle dichiarazioni di $ tabname e $ num sono cruciali: contesto di array vs contesto scalare.

Altri suggerimenti

Un'opzione è di non usare RaiseError = > 1 durante la costruzione di $ dbh. L'altro è avvolgere la preparazione in un blocco di valutazione.

Basta inserire le chiamate che potrebbero fallire in un blocco eval come questo:

for my $table (@tables) {
    my $count;
    eval {
        ($count) = $dbi->selectrow_array("select count(*) from $table");
        1; #this is here so the block returns true if it succeeds
    } or do {
        warn $@;
        next;
    }
    print "$table has $count rows\n";
}

Anche se, in questo caso, poiché stai utilizzando Informix, hai un'opzione molto migliore: le tabelle del catalogo di sistema. Informix mantiene i metadati in questo modo in una serie di tabelle del catalogo di sistema. In questo caso vuoi systables:

my $sth = $dbh->prepare("select nrows from systables where tabname = ?");
for my $table (@tables) {
    $sth->execute($table);
    my ($count) = $sth->fetchrow_array;
    $sth->finish;
    unless (defined $count) {
        print "$table does not exist\n";
        next;
    }
    print "$table has $count rows\n";
} 

Questo è più veloce e sicuro del count (*) rispetto alla tabella. La documentazione completa delle tabelle del catalogo di sistema è disponibile in IBM Informix Guide to SQL (attenzione questo è un PDF).

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