Seitdem sie mit SQL-Server-2005 eingeführt wurde, bin ich ein Fan der neuen Fehlerbehandlung. Deswegen empfahl ich deren Einsatz auch gleich in unseren Richtlinien. Leider mussten wir kürzlich feststellen, dass sie unerwartete Nebenwirkungen hat.

Wir setzen bei uns ganz gerne Stored-Procedure und Functions ein. Nicht nur wegen der – in der Regel – besseren Performance gegenüber den Alternativen, sondern auch weil man deren Implementierung ändern kann ohne das Anwendungscoding anpassen zu müssen. Jetzt hat ein Kollege in seine Stored-Procedure die alte @@ERROR-Fehlerbehandlung durch die Neue mit TRY-CATCH ersetzt und bekam einen hässlichen Fehler. Wir konnten das ganz leicht reproduzieren und sind im Gespräch mit Microsoft über das Verhalten.

  • Man benötigt eine Client-Anwendung, die Daten aus einer Stored-Procedure über einen Cursor liest. In unserem Fall war das eine Windows-32-Anwendungen auf Basis MFC/ODBC, aber das ist fast egal: Mit ADO/OLEDB passiert das gleiche, weil sich der Server komisch verhält.
  • Die Anwendung öffnet einen Cursor, der auch rückwärts navigieren kann, also z.B. static. (Um das mit ODBC zu reproduzieren, muss man mit Srever-Cursors arbeiten. Man darf hier also nicht die Client-Library verwenden, weil damit die kompletten Daten in einen Cache am Client geladen werden und dann dort navigiert wird. Aber wer holt sich diese Spaßbremse schon freiwillig ins Boot, sie wurde eingeführt um ODBC-Treibern ohne Cursor-Unterstützung auf die Sprünge zu helfen. Auf Kosten der Performance…)
  • Das ResultSet kommt aus einer Procedure P1, die im einfachsten Fall nur ein einzelnes SELECT enthält.
  • Die Anwendung öffnet den Cursor, liest ein paar Sätze und springt dann wieder zum ersten Datensatz.

Wenn in der Stored-Procedure nun ein TRY-CATCH um das SELECT gemacht wird, dann treten in dem Szenario plötzlich ein Fehler auf, weil der Rücksprung auf dem Cursor nicht mehr möglich ist. Auch parallel geöffnete, andere Client-Cursor – auf der gleichen Connection – können nicht mehr parallel gelesen werden.

Das liegt daran, dass der SQL-Server anstelle des Static-Cursors auf der Server-Seite plötzlich ein Default-ResultSet ("forward-only/read-only", auch als "Firehose"-Cursor" bekannt) verwendet. Und das kann freilich keine Rücksprünge. Das Default-ResultSet belegt ja bekanntlich auch die ganze Connection und verhindert das andere Cursor ausgelesen werden bis das Default-ResultSet wieder geschlossen wurde. (MARS hilft bei Verwendung der "alten" Schnittstellen wir MFC übrigens auch nicht wirklich weiter.) Schade, dass das von Microsoft nicht dokumentiert wurde.

Wer denkt, er sei mit seiner .Net-Anwendung aus dem Schneider, den muss ich leider enttäuschen, auch hier werden unter der Haube Cursors verwendet, um die Daten auszulesen. Aber freilich kommt es in der Regel nicht vor, dass auf den Cursors rumnavigiert wird.

Daher werden wir wohl empfehlen müssen, dass die neue Fehlerbehandlung genau dann nicht eingesetzt wird, wenn das ResultSet mit einem Cursor ausgelesen wird, auf dem entweder rauf und runter navigiert wird oder parallel auf andere Cursor zugegriffen wird. Leider ist das bei den meisten unserer bestehen Windows-32-Anwendungen so. Erst die neue Programmgeneration geht anders vor…