如果没有影响任何行,为什么DBI的do方法会返回"0E0"?

24

我在运行类似以下示例代码时遇到了问题:

my $rows = $dbh->do('UPDATE table SET deleted=NOW() WHERE id=?', undef, $id) 
  or die $dbh->errstr;
if (!$rows) {
  # do something else
}

由于文档中指出do返回受影响的行数,因此我认为那样做能行。

准备并执行单个语句。返回受影响的行数或错误的undef。返回值-1表示行数未知、不适用或不可用。

事实证明,我错了。当我调试它时,我看到$rows实际上保存了字符串0E0,这当然是一个真值。我进一步查看了文档并看到这段代码:

默认的do方法在逻辑上类似于:

  sub do {
      my($dbh, $statement, $attr, @bind_values) = @_;
      my $sth = $dbh->prepare($statement, $attr) or return undef;
      $sth->execute(@bind_values) or return undef;
      my $rows = $sth->rows;
      ($rows == 0) ? "0E0" : $rows; # always return true if no error
  }
那就是它了。它返回0E0。我不明白为什么会这样。有人知道吗?

1
哈哈,你的技能已经有所提高了。:-) 我喜欢这个问题。这是一个非常好的通用兴趣问题的范例。 - PerlDuck
@PerlDuck 是的,这是一段时间以前的事了。但我会称之为特定的“知识”,而不是“技能”。但我的技能肯定也有所提高。顺便问一下,我会在伦敦见到你吗? - simbabque
很抱歉,虽然我很想参加,但那个周末对我来说不行 :-( - PerlDuck
@PerlDuck 真遗憾。然而,德国 Perl 工作坊 2018(这是第20届周年纪念!)将于明年春天在 Bergisch-Gladbach 举行。如果我没记错的话,那对你来说就在附近,所以没有理由不去!;) - simbabque
1个回答

29

这是一个真实的值,因此您可以将其与错误时返回的假值区分开来,但它在数值上等于零(没有警告),因此仍然等于受影响的记录数。

$ perl -e'
   for (undef, "0E0", 4) {
      if ($_) {
         printf "Success: %d rows affected\n", $_;
      } else {
         print "Error!\n";
      }
   }
'
Error!
Success: 0 rows affected
Success: 4 rows affected
如果在没有受影响的记录时返回0表示成功,那么你就必须使用defined来检查错误,这比测试真实值要不方便得多(例如:foo() or die;)。 其他真正的零值。(忽略"0x0";它会发出警告。)

1
还有另一个特殊值“0但为真”,它具有相同的目的。 - mvp
2
@mvp,从技术上讲,““0 but true””是唯一的特殊编码情况,但有十几种方法可以实现这一点。(该页面上的“0x0”是错误的;它会发出警告。) - ikegami
我喜欢那个perlmonks链接上的解释。你应该把它加到你的答案中。 - simbabque
@simbabque,您指的是哪个回复? - ikegami
我指的是您上面链接中的*指数("0E0")*。它在perlnumber中有解释。 - simbabque
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接