2

首先(如果这很重要)我使用的是 ActiveState 的 Perl(为 MSWin32-x86-multi-thread 构建的 v5.8.7)。

我刚刚从长达三个小时的调试会议中走出来,试图找到错误的根源。我发现根本没有错误,但由于某种原因,ADO 的连接对象Errors.Count随着存储过程输出中的每条打印消息而增加。

考虑以下 Transact SQL 代码:

CREATE PROCEDURE dbo.My_Sample() AS
BEGIN TRAN my_tran
-- Does something useful
if @@error <> 0 BEGIN
  ROLLBACK TRAN my_tran
  RAISERROR( 'SP My_Sample failed', 16, 1)
END ELSE BEGIN
  COMMIT TRAN my_tran
  PRINT 'SP My_Sample succeeded'
END

现在想象一个 Perl sub 或多或少像:

sub execute_SQL {
  # $conn is an already opened ADO connection object
  # pointing to my SQL Server
  # $sql is the T-SQL statement to be executed
  my($conn, $sql) = @_;
  $conn->Execute($sql);
  my $error_collection = $conn->Errors();
  my $ecount = $error_collection->Count;
  if ($ecount == 0 ) { return 0; }
  print "\n" . $ecount . " errors found\n";
  print "Executed SQL Code:\n$sql\n\n";
  print "Errors while executing:\n";
  foreach my $error (in $error_collection){
    print "Error: [" . $error->{Number} . "] " . $error->{Description} . "\n";
  }
  return 1;
}

在其他地方,在主 Perl 代码中,我将上面的子代码称为:

execute_SQL( $conn, 'EXEC dbo.My_Sample' );

最后,我知道每个PRINT 语句都会导致一个新的伪错误附加到 ADO 错误集合中。我实施的快速修复是将 SP 中的 PRINT 更改为 SELECT,以绕过它。

我想问的问题是:

  • 这种行为正常吗?
  • 有没有办法避免/绕过它?
4

2 回答 2

4

这是意料之中的,因为它是 ADO 所做的,而 Win32::ADO 在它之上是相当薄的一层。

ref: 知识库注意,RAISERROR 和 PRINT 语句是通过 ADO 错误集合返回的

于 2008-10-21T22:05:55.010 回答
1

好的,经过大量的测试和阅读,我发现它在 BOL 的文章“使用 PRINT”中进行了解释(我的重点):

PRINT 语句用于向应用程序返回消息。PRINT 将字符或 Unicode 字符串表达式作为参数,并将字符串作为消息返回给应用程序。该消息作为信息错误返回给使用 SQLClient 命名空间或 ActiveX 数据对象 (ADO)、OLE DB 和开放式数据库连接 (ODBC) 应用程序编程接口 (API) 的应用程序。SQLSTATE 设置为 01000,本机错误设置为 0,错误消息字符串设置为 PRINT 语句中指定的字符串。该字符串返回给 DB-Library 应用程序中的消息处理程序回调函数。

有了这些知识,我从这篇 DevX 文章中改编了这个 VB6,直到我得到这个:

sub execute_SQL {
  # $conn is an already opened ADO connection object
  # pointing to my SQL Server
  # $sql is the T-SQL statement to be executed
  # Returns 0 if no error found, 1 otherwise
  my($conn, $sql) = @_;
  $conn->Execute($sql);
  my $error_collection = $conn->Errors();
  my $ecount = $error_collection->Count;
  if ($ecount == 0 ) { return 0; }

  my ($is_message, $real_error_found);
  foreach my $error (in $error_collection){
    $is_message = ($error->{SQLState} eq "01000" && $error->{NativeError}==0);
    $real_error_found=1 unless $is_message;

    if( $is_message) {
      print "Message # " . $error->{Number}
      . "\n Text: " . $error->{Description} ."\n";
    } else {
      print "Error # " . $error->{Number}
      . "\n Description: " . $error->{Description}
      . "\nSource: " . $error->{Source} . "\n";
    }
  }

  print $message_to_print;
  return $real_error_found;
}

所以现在我的 Perl 子程序正确地整理出真正的错误(通过 RaisError 从 SQL Server 发出)和通过“PRINT”输出的常见消息。

感谢 Richard Harrison 的回答,让我走上了成功之路。

于 2008-10-22T18:37:03.527 回答