¿Cómo puedo evitar que el programa se cierre cuando el DBI de Perl encuentra un error al preparar una declaración?

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

  •  08-07-2019
  •  | 
  •  

Pregunta

Estoy creando un script que pasa por una tabla que contiene todos los otros nombres de tabla en la base de datos. A medida que analiza cada fila, comprueba si la tabla está vacía

select count(*) cnt from $table_name 

Algunas tablas ya no existen en el esquema y si lo hago

select count(*) 

directamente en el símbolo del sistema, devuelve el error:

  

206: La tabla especificada (adm_rpt_rec) no está en la base de datos.

Cuando lo ejecuto desde Perl, agrega esto al principio:

  

DBD :: Informix :: db prepare falló: SQL: -

¿Cómo puedo evitar que el programa se cierre cuando intenta preparar esta declaración SQL?

¿Fue útil?

Solución

Código de trabajo: suponiendo que tenga una base de datos de 'tiendas'.

#!/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";

Salida de ejecutar el código anterior.

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.

Esto imprimió el error ( PrintError = > 1 ), pero continuó. Cambie el 1 a 0 y no aparecerá ningún error. Los paréntesis en las declaraciones de $ tabname y $ num son cruciales: contexto de matriz versus contexto escalar.

Otros consejos

Una opción es no usar RaiseError = > 1 al construir $ dbh. El otro es envolver la preparación en un bloque eval.

Simplemente coloque las llamadas que pueden fallar en un bloque de evaluación como este:

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";
}

Aunque, en este caso, dado que está utilizando Informix, tiene una opción mucho mejor: las tablas del catálogo del sistema. Informix mantiene metadatos como este en un conjunto de tablas de catálogo del sistema. En este caso, quiere sílabas:

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";
} 

Esto es más rápido y seguro que count (*) en la tabla. La documentación completa de las tablas del catálogo del sistema se puede encontrar en Guía de IBM Informix para SQL (advertencia de que se trata de un PDF).

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