2

まず第一に (これが重要な場合に備えて) 私は ActiveState の Perl (MSWin32-x86-multi-thread 用にビルドされた v5.8.7) を使用しています。

エラーの原因を突き止めようとして、3 時間にわたるデバッグ セッションから抜け出しました。エラーはまったくないことがわかりましたが、何らかの理由Errors.Countで、ストアド プロシージャの出力に出力されるメッセージごとに ADO の接続オブジェクトが増加していました。

次の 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 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

OK、多くのテストと読書の後、BOLの記事「Using PRINT」で説明されていることがわかりました(私の強調):

PRINT ステートメントは、アプリケーションにメッセージを返すために使用されます。PRINT は、文字または Unicode 文字列式をパラメーターとして取り、その文字列をメッセージとしてアプリケーションに返します。このメッセージは、SQLClient 名前空間または ActiveX データ オブジェクト (ADO)、OLE DB、および Open Database Connectivity (ODBC) アプリケーション プログラミング インターフェイス (API) を使用するアプリケーションに情報エラーとして返されます。SQLSTATE は 01000 に設定され、ネイティブ エラーは 0 に設定され、エラー メッセージ文字列は PRINT ステートメントで指定された文字列に設定されます。文字列は、DB-Library アプリケーションのメッセージ ハンドラ コールバック関数に返されます。

この知識を武器に、この VB6 をこの DevX 記事から次のように修正しました。

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" を介して出力された一般的なメッセージを正しく分類します。

私を成功へと導いてくれたリチャード・ハリソンに感謝します。

于 2008-10-22T18:37:03.527 に答える