Perl错误:在连接中使用未初始化的值$ DBI :: err

时间:2015-12-07 10:48:25

标签: perl dbi

我写了一个过程,它使用库DBI将数据从xml文件导入MariaDB。该过程有效,但我不明白为什么以下代码给我的信息:

use of uninitialized value $DBI::err in concatenation (.) or string at ...

这里的代码(缩写):

my $insert_art = $dbh->prepare(
    "INSERT INTO odbb_articles (creation_dt,ref_data,comp_no)". 
     "VALUES (?,?,?)"
);
....
my $comp_no = $xpc->findvalue('./sr:ARTCOMP/sr:COMPNO',$node1);
....
$insert_art->execute($creation_dt,$ref_data,$comp_no)
or die "Fehler bei der Ausfuehrung: ".
       "$DBI::err -> $DBI::errstr (odbb_articles $DBI::state)\n"; 

如果我插入代码

if ($comp_no eq "") { $comp_no = undef; }

$ insert_art->执行之前,该过程有效。当元素COMPNO的xml文件中没有条目时,会发生此错误。如果我把它定义为undef,我可以避免它。我只是想知道

  1. 为什么$ comp_no导致此问题和
  2. 是否有另一种解决方案,而不是控制$ comp_no是否为“”并将其定义为undef?
  3. 第二个问题的原因是如果有很多变量/列可能有空条目,则避免使用if语句。

    感谢您的帮助。

3 个答案:

答案 0 :(得分:2)

在SQL数据库中,空字符串与null非常不同。 如果comp_no有一个外键指向另一个表中的记录,那么值""只有在有""的记录时才是可加入的。作为主键,非常不可能。

Yu可以修复将空值转换为 undef

的问题
for ($creation_dt,$ref_data,$comp_no ){
  defined $_  and $_ eq '' and  $_ =  undef;
}
$insert_art->execute($creation_dt,$ref_data,$comp_no);

$insert_art->execute(map {defined($_) && length($_) ? $_ : undef} ($creation_dt,$ref_data,$comp_no));

答案 1 :(得分:2)

  

在连接(。)或字符串中使用未初始化的值$ DBI :: err ...

您看到的错误消息是Perl告诉您$DBI::errundef。这不是因为$comp_no的价值。这只是你的计划正在做的结果。

因此,当您将空字符串传递给comp_no列时,数据库并不喜欢这样。它抛出一个错误。 DBI捕获该错误并将其传递。 $insert_art->execute返回false值,并调用or的右侧。那是你的die

现在,在传递给die的字符串中,您放了三个变量:

  • $DBI::err
  • $DBI::errstr
  • $DBI::state

根据the DBI documentation,这些功能相当于$h->err$h->errstr$h->state,其中$h最后使用的句柄。让我们来看看那些文档。

  • $h->err

      

    从最后一个调用的驱动程序方法返回本机数据库引擎错误代码。代码通常是一个整数,但你不应该假设。

         

    DBI在几乎所有DBI方法调用之前将$ h-> err重置为undef,因此该值仅具有较短的生命周期。此外,对于大多数驱动程序,语句句柄与父数据库句柄共享相同的错误变量,因此在一个句柄上调用方法可能会重置相关句柄上的错误。 [...]

    这不能解释何时可以undef

  • $h->errstr

      

    从最后一个调用的DBI方法返回本机数据库引擎错误消息。这与" err"具有相同的寿命问题。上述方法。

         

    返回的字符串可能包含由换行符分隔的多条消息。

         

    不应该使用errstr()方法来测试错误,为此使用err(),因为驱动程序可能会返回信息'或者通过errstr()发出警告信息,告知没有失败的方法'。

    好的,这是文字。不要用它来测试特定的错误。你不是那样做的。您只想在程序失败时提供调试输出。

  • $h->state

      

    以标准SQLSTATE五字符格式返回状态代码。请注意,特定成功代码00000将转换为任何空字符串(false)。如果驱动程序不支持SQLSTATE(并且大多数不支持),则state()将返回所有错误的S1000(常规错误)。

         

    驱动程序可以通过状态自由返回任何值,例如警告代码,即使它没有通过" err"返回真值来声明错误。上述方法。

         

    不应该使用state()方法来测试错误,为此使用err(),因为驱动程序可能会返回信息'或者通过state()警告状态代码,用于没有'失败的方法。

    同样,这不是很清楚它的用途。

我的建议是摆脱$DBI::err$DBI::state。你不需要那些来弄清问题是什么。只需输出$DBI::errstr

$insert_art->execute($creation_dt,$ref_data,$comp_no)
  or die "Fehler bei der Ausfuehrung: " . $dbh->errstr;

现在您的程序仍然会失败,但至少您会收到一条有意义的错误消息,说明您的数据库对该语句的不满意。这比告诉您的错误处理代码中存在错误更好。

之后,其他答案可能适用于解决在第一种情况下发生这种情况的原因。

另一方面,die上有一个单词:如果在参数末尾提供\n,则不会打印当前脚本,行号和输入句柄行号。但那些可能对你的情况有用。你可以加入它们。

答案 2 :(得分:1)

这是一种可能的捷径:

$comp_no ||= undef;

需要注意的是,在$comp_no评估为false的情况下,这将起作用,意味着值0实际上会导致结果也为undef,这对您来说可能或不重要。如果你的字段是数字的,我会说这很重要。