Perl ADO считает вывод на печать в хранимой процедуре ошибкой! - PullRequest
2 голосов
/ 22 октября 2008

Прежде всего (в случае, если это важно) я использую Perl ActiveState (v5.8.7, построенный для многопоточности MSWin32-x86).

Я только что вышел из трехчасового сеанса отладки, пытаясь найти источник ошибки. Я обнаружил, что ошибки просто не было, но по какой-то причине объект соединения 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 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. Быстрое исправление, которое я реализовал, состояло в том, чтобы превратить PRINT в SP в SELECT, чтобы обойти это.

Я хотел бы задать следующие вопросы:

  • Это нормальное поведение?
  • Есть ли способ избежать / обойти это?

Ответы [ 2 ]

4 голосов
/ 22 октября 2008

Этого следует ожидать, так как это то, что делает ADO, а Win32 :: ADO довольно тонкий слой над ним.

ref: база знаний обратите внимание, что операторы RAISERROR и PRINT возвращаются через коллекцию ошибок ADO

1 голос
/ 22 октября 2008

ОК, после лота тестирования и чтения, я обнаружил, что это объяснено в статье BOLs "Использование PRINT" (мой акцент):

Оператор PRINT используется для возврата сообщений в приложения. PRINT принимает в качестве параметра символьное или строковое выражение Unicode и возвращает строку в виде сообщения приложению. Сообщение возвращается как информационная ошибка приложениям, использующим пространство имен SQLClient или интерфейсы прикладного программирования (API) приложений ActiveX Data Objects (ADO), OLE DB и Open Database Connectivity (ODBC). SQLSTATE установлен на 01000, собственная ошибка установлена ​​на 0, а строка сообщения об ошибке установлена ​​на строку символов, указанную в операторе PRINT. Строка возвращается в функцию обратного вызова обработчика сообщений в DB Библиотека приложений.

Вооружившись этим знанием, я адаптировал этот 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 правильно сортирует реальные ошибки (исходящие от SQL Server через RaisError) и обычное сообщение, выводимое через «PRINT».

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

...