Pregunta

Primero que todo (en caso de que esto sea importante) estoy usando Perl de ActiveState (v5.8.7 creado para MSWin32-x86-multi-thread).

Acabo de salir de una sesión de depuración de tres horas de duración, tratando de encontrar la fuente de un error. Descubrí que simplemente no había ningún error, pero por alguna razón, el objeto de conexión de ADO estaba obteniendo un aumento de Errors.Count con cada mensaje impreso en la salida de mi procedimiento almacenado.

Considere el siguiente código 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

Ahora imagine un submarino de Perl más o menos como:

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;
}

En otro lugar, en el código principal de Perl, llamo al subcomité anterior como:

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

Al final, obtuve que cada PRINT hace que se agregue un nuevo seudo error a la colección de errores de ADO. La solución rápida que implementé fue cambiar esa IMPRESIÓN en el SP a SELECT, para evitar esto.

Las preguntas que me gustaría hacer son:

  • ¿Es normal este comportamiento?
  • ¿Hay alguna forma de evitarlo / evitarlo?
¿Fue útil?

Solución

Esto es de esperar, ya que es lo que hace ADO y Win32 :: ADO es una capa bastante delgada por encima de él.

ref: Knowledge Base tenga en cuenta que las declaraciones RAISERROR y PRINT se devuelven a través de la colección de errores ADO

Otros consejos

Bien, después de un lote de pruebas y lecturas, llegué a encontrarlo explicado en el artículo de BOLs " Uso de IMPRIMIR " (mi énfasis):

  

La instrucción PRINT se usa para devolver mensajes a las aplicaciones. PRINT toma un carácter o una expresión de cadena de Unicode como parámetro y devuelve la cadena como un mensaje a la aplicación. El mensaje se devuelve como un error informativo a las aplicaciones que utilizan el espacio de nombres SQLClient o las interfaces de programación de aplicaciones (API) de ActiveX Data Objects (ADO), OLE DB y Open Database Connectivity (ODBC). SQLSTATE se establece en 01000, el error nativo se establece en 0 y la cadena de mensaje de error se establece en la cadena de caracteres especificada en la declaración PRINT. La cadena se devuelve a la función de devolución de llamada del manejador de mensajes en DB -Aplicaciones de biblioteca.

Armado con este conocimiento, adapté este VB6 de este artículo de DevX hasta que obtuve esto:

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;
}

Así que ahora mi sub Perl resuelve correctamente los errores reales (emitidos desde SQL Server a través de un RaisError) y un mensaje común emitido a través de " PRINT " ;.

Gracias a Richard Harrison por su respuesta que me llevó al camino del éxito.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top