Как я могу избежать выхода из программы, когда DBI Perl сталкивается с ошибкой при подготовке оператора? - PullRequest
1 голос
/ 08 мая 2009

Я делаю сценарий, который проходит через таблицу, которая содержит все другие имена таблиц в базе данных. Когда он анализирует каждую строку, он проверяет, пуста ли таблица, на

select count(*) cnt from $table_name 

Некоторые таблицы больше не существуют в схеме, и если я это сделаю

select count(*) 

прямо в командную строку, возвращается ошибка:

206: указанной таблицы (adm_rpt_rec) нет в базе данных.

Когда я запускаю его изнутри Perl, он добавляет это в начало:

DBD :: Informix :: db подготовить не удалось: SQL: -

Как я могу избежать выхода из программы при попытке подготовить этот оператор SQL?

Ответы [ 3 ]

3 голосов
/ 08 мая 2009

Просто поместите вызовы, которые могут потерпеть неудачу, в блок eval, например:

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

Хотя в этом случае, поскольку вы используете Informix, у вас есть гораздо лучший вариант: таблицы системного каталога. Informix хранит метаданные подобным образом в наборе таблиц системного каталога. В этом случае вам нужны 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";
} 

Это быстрее и безопаснее, чем count(*) против стола. Полная документация таблиц системного каталога находится в IBM Informix Guide to SQL (предупреждение, что это PDF).

3 голосов
/ 08 мая 2009

Один вариант - не использовать RaiseError => 1 при построении $ dbh. Другой - завернуть приготовление в блок eval.

2 голосов
/ 08 мая 2009

Рабочий код - при условии, что у вас есть база данных магазинов.

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

Вывод из выполнения кода выше.

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.

Это напечатало ошибку (PrintError=>1), но продолжилось. Измените 1 на 0, и ошибка не появится. Скобки в объявлениях $tabname и $num имеют решающее значение - контекст массива против скалярного контекста.

...