Wie der Treiber Antworten einordnet und meldet
graph TD
A["Antwort des Dienstes oder Abbruch der Verbindung"] --> B{"HTTP-Status"}
B -->|"2xx"| C{"Form passt zur Anfrage?"}
C -->|"ja"| D["Ergebnis: Zeilen, Anzahl oder betroffene Sätze"]
C -->|"nein"| X["08S01: Antwort unbrauchbar"]
B -->|"401, 403 mit Herausforderung"| H["Code oder Identität erfragen, Anfrage einmal neu senden"]
B -->|"4xx mit Meldungen der Datenbank"| E["je Meldung ein Diagnosesatz mit Nummer und SQLSTATE"]
B -->|"übrige 4xx, 5xx, 504"| F["ein Diagnosesatz mit dem HTTP-Status als Nummer"]
A -->|"Verbindung abgebrochen"| W["wiederholen, wo unschädlich; sonst 08S01"]Abbildung: Der Treiber entscheidet zuerst nach dem HTTP-Status, danach nach der Form, die für die gestellte Anfrage zu erwarten ist. Inhalt und Form eines Erfolgs beschreibt Wie aus einem OData-Dienst ein relationales ODBC-Modell wird.
Eine HTTP-Antwort ist nicht von selbst ein Ergebnis im Sinne von ODBC: Sie kann Daten tragen, eine Ablehnung des Dienstes, Meldungen der Datenbank oder eine Form, mit der der Treiber nichts anfangen kann. Diese Seite legt für jede Klasse von Antworten fest, welchen Rückgabewert die Anwendung erhält, welche Diagnosesätze (SQLSTATE, native Fehlernummer, Text) entstehen und in welchem Zustand Anweisung und Verbindung danach sind.
Wichtige Funktionen
- Erfolg nur bei passender Form: Ein
200mit unlesbarem oder unerwartetem Inhalt ist kein Erfolg. - Meldungen der Datenbank wie über eine direkte Verbindung: Nummer, SQLSTATE und Text je Meldung.
- Keine erfundenen Ergebnisse: Eine abgebrochene oder vom Dienst gekürzte Antwort wird nicht als vollständig gemeldet.
Grundkonzepte
Klassen von Antworten
| Klasse | Erkannt an | Rückgabe an die Anwendung | Diagnosesatz | Zustand danach |
|---|---|---|---|---|
| Daten | 2xx, Sammlung mit value (Lesen) bzw. columns (Durchreiche) | SQL_SUCCESS; Zeilen über SQLFetch | keiner | Cursor offen |
| Änderung ausgeführt | 2xx auf POST, PATCH, DELETE | SQL_SUCCESS, SQLRowCount = 1 (Aktionen für Tabellen ohne Schlüssel: die genannte Zahl) | keiner | – |
| Änderung trifft keinen Satz | 404 oder 412 auf PATCH/DELETE | SQLRowCount = 0 – Access zeigt daraus seinen Schreibkonflikt | keiner | – |
| Zweiter Faktor verlangt | 401 mit WWW-Authenticate: Wkl-Totp | nach Codeeingabe das Ergebnis der wiederholten Anfrage; ohne Dialog SQL_ERROR | 28000 mit der Meldung des Dienstes | – |
| Identität zu wählen | 403 mit X-Wkl-Roles | nach der Wahl das Ergebnis der wiederholten Anfrage; ohne Dialog SQL_ERROR | 28000 | – |
| Anmeldung abgelehnt | übriges 401 oder 403 | SQL_ERROR | 28000, native Nummer = HTTP-Status | – |
| Meldungen der Datenbank | 4xx mit error.details, deren code eine Zahl ist | SQL_ERROR | ein Satz je Meldung, höchstens 20: SQLSTATE aus sqlState (fehlt er: 42000), native Nummer = Meldungsnummer, Text der Meldung | eine offene Transaktion bleibt offen |
| Übrige Ablehnung | 4xx ohne solche Meldungen | SQL_ERROR | 42000, native Nummer = HTTP-Status, Text aus error.message oder die ersten 200 Zeichen des Rumpfs | – |
| Ergebnis gekürzt | "truncated": true in der Antwort der Durchreiche: die Zeilenobergrenze des Dienstes griff | SQL_SUCCESS für die gelieferten Zeilen, danach SQL_ERROR beim nächsten SQLFetch | HY000 „Der Dienst hat das Ergebnis nach N Zeilen gekürzt (Zeilenobergrenze des Dienstes); es ist unvollständig.“ – das Kennzeichen steht hinter den Zeilen, früher kann der Treiber es nicht wissen | die gelieferten Zeilen bleiben geliefert; die Anweisung endet |
| Umleitung | 3xx mit Location | beim Lesen am selben Ursprung: das Ergebnis der Zieladresse; sonst SQL_ERROR | 08S01 mit dem Ziel; der Treiber folgt keiner Umleitung an einen anderen Ursprung und wiederholt keine umgeleitete Änderung | – |
| Zeitgrenze | 504 oder die eigene Zeitgrenze des Treibers | SQL_ERROR | HYT00; nicht wiederholt, weil der Dienst womöglich noch arbeitet | Ergebnis einer Änderung unbekannt |
| Dienst gestört | 5xx außer 504 | SQL_ERROR | 08S01, native Nummer = HTTP-Status | – |
| Transaktion zurückgenommen | 409 beim Abschluss | SQL_ERROR aus SQLEndTran | 40001 | nichts aus der Transaktion gespeichert |
| Verbindung abgebrochen | keine Antwort | nach Wiederholung (siehe unten) das Ergebnis; sonst SQL_ERROR | 08S01 | – |
| Zertifikat nicht vertraut | TLS-Fehler | SQL_ERROR, ohne Wiederholung | 08S01 mit Grund, etwa „UntrustedRoot“ | – |
| Antwort unbrauchbar | 2xx mit ungültigem JSON, ohne value bzw. columns, mit einem Wert, der nicht zum angekündigten Typ passt, oder ein Strom, der mittendrin endet | SQL_ERROR | 08S01 mit einer Meldung, die den Mangel nennt | die Anweisung endet mit dem Fehler; bereits gelieferte Zeilen bleiben geliefert |
| Fehler im Treiber | jede andere Ausnahme | SQL_ERROR | HY000 „Unerwarteter Fehler: …“; die vollständige Ausnahme steht in der Ablaufverfolgung | – |
Eine Antwort, die eine dieser Formen hat, aber ein Feld mehr trägt als erwartet, gilt als passend: Unbekannte Felder und Annotationen übergeht der Treiber. Das hält ihn mit späteren Versionen eines Dienstes verträglich, hat aber eine Folge, die unter Grenzen steht.
Warum 08S01 für eine unbrauchbare Antwort. ODBC kennt keinen eigenen SQLSTATE für „Gegenstelle
antwortet nicht protokollgerecht“. 08S01 („Communication link failure“) sagt der Anwendung, was zu
tun ist: Die Anweisung selbst ist nicht falsch, das Gegenüber ist es; eine Wiederholung mit derselben
Anweisung kann gelingen, wenn der Dienst wieder richtig antwortet. Die Meldung unterscheidet den Fall
von einem Netzausfall.
Warnungen
ODBC meldet eine Warnung als SQL_SUCCESS_WITH_INFO mit einem Diagnosesatz der Klasse 01. Dieser
Treiber erzeugt Warnungen nur selbst:
| SQLSTATE | Anlass |
|---|---|
01004 | ein Wert war länger als der Puffer der Anwendung und wurde gekürzt geliefert |
01S02 | die Anwendung verlangte einen Cursor, den der Treiber nicht hat; er arbeitet vorwärts lesend ohne Sperren weiter |
Hinweise der Datenbank bei einem Erfolg erreichen die Anwendung nicht. Sendet die Datenbank zu
einer erfolgreichen Anweisung eine Meldung (in SQL Server etwa PRINT oder RAISERROR mit Schwere
bis 10), erhält die Anwendung über den Treiber von SQL Server SQL_SUCCESS_WITH_INFO mit dieser
Meldung. Über diesen Treiber kommt SQL_SUCCESS ohne sie: Der Datendienst Wkl.Data.Gateway gibt Meldungen nur
mit einer Ablehnung weiter, und der Treiber liest in einer erfolgreichen Antwort keine. Ein begleitender Hinweis
zu einer Ablehnung (SQLSTATE 01000) erscheint dagegen als weiterer Diagnosesatz des Fehlers.
Wiederholung nach einem Abbruch
Bricht die Verbindung ohne Antwort ab, wiederholt der Treiber nach 1 und nach 3 Sekunden: Lesen immer,
Änderungen und gesammelt gelesene eigene Anweisungen mit demselben Idempotency-Key. Nicht wiederholt
werden eine überschrittene Zeitgrenze, der Abschluss einer Transaktion und eine gestreamte eigene
Anweisung; mit RETRY=OFF gar nichts. Wann das für welchen Dienst sicher ist, steht unter
Zusagen je Art des Dienstes.
Sprache der Meldungen
Der Text eines Diagnosesatzes folgt der Anzeigesprache des Windows-Benutzers, unter dem die Anwendung
läuft: Deutsch, Slowenisch, sonst Englisch; ebenso die Dialoge des Treibers. Maßgeblich ist Windows,
nicht eine Sprache, die eine Anwendung wie Office für sich einstellt. SQLSTATE und native
Fehlernummer sind in jeder Sprache dieselben – eine Anwendung, die Fehler auswertet, prüft diese und
nicht den Text. Meldungen des Dienstes und der Datenbank gibt der Treiber unverändert weiter, in der
Sprache, in der sie dort entstehen. Die eigenen Zeilen der Ablaufverfolgung bleiben deutsch; ein
Diagnosesatz steht dort (DIAG) so, wie ihn die Anwendung erhielt. Eine Anwendung, die Meldungen
schmal liest (SQLGetDiagRecA), erhält sie in ihrer ANSI-Codepage; slowenische Buchstaben (č, š, ž)
enthält nur die Codepage 1250 (Mitteleuropäisch), die ANSI-Codepage eines slowenischen Windows.
Grenzen
| Grenze | Folge |
|---|---|
| Nur die erste Ergebnismenge der Durchreiche kommt Zeile für Zeile | weitere Mengen (results) liegen nach dem Ende der ersten im Speicher; Ausgabewerte (outputs) stehen in den Puffern, sobald SQLMoreResults SQL_NO_DATA meldet, bei einer Anweisung ohne Ergebnismenge gleich nach dem Ausführen |
| Hinweise der Datenbank zu einem Erfolg werden nicht weitergegeben | kein SQL_SUCCESS_WITH_INFO |
Verwandte Themen
- „Der Dienst hat das Ergebnis nach N Zeilen gekürzt“ – was zu tun ist
- „Der Dienst leitet an … um“ – was zu tun ist
- Wie der Treiber Anweisungen übersetzt: Meldungen der Datenbank – wie Access, DAO und ADO.NET die Sätze zeigen
- So schalten Sie die Ablaufverfolgung ein – die Meldung hinter einem Fehler finden