Perl ADO считает вывод на печать в хранимой процедуре ошибкой!

Прежде всего (в случае, если это важно), я использую 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 ответа

Решение

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

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

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

Оператор PRINT используется для возврата сообщений в приложения. PRINT принимает символьное или строковое выражение Unicode в качестве параметра и возвращает строку в виде сообщения в приложение. Сообщение возвращается как информационная ошибка приложениям, использующим пространство имен SQLClient или интерфейсы прикладного программирования (API) приложений ActiveX Data Objects (ADO), OLE DB и Open Database Connectivity (ODBC). 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 правильно сортирует реальные ошибки (исходящие от SQL Server через RaisError) и общее сообщение, выводимое через "PRINT".

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

Другие вопросы по тегам