Color scheme: Dark
You are here: start » en » Documentation » Data integration and data access » WKL OData ODBC Driver » OData ODBC driver concepts » How the driver classifies and reports responses

How the driver classifies and reports responses

graph TD
    A["Response from the service or dropped connection"] --> B{"HTTP status"}
    B -->|"2xx"| C{"Shape matches the request?"}
    C -->|"yes"| D["Result: rows, count, or affected records"]
    C -->|"no"| X["08S01: response unusable"]
    B -->|"401, 403 with challenge"| H["Ask for code or identity, send the request again once"]
    B -->|"4xx with database messages"| E["one diagnostic record per message with number and SQLSTATE"]
    B -->|"other 4xx, 5xx, 504"| F["one diagnostic record with the HTTP status as the number"]
    A -->|"connection dropped"| W["retry where harmless; otherwise 08S01"]

Figure: The driver decides first by the HTTP status, then by the shape that's to be expected for the request made. The content and shape of a success are described in How an OData service becomes a relational ODBC model.

An HTTP response isn't automatically a result in the ODBC sense: it can carry data, a rejection by the service, database messages, or a shape that the driver can't make use of. This page specifies, for every class of response, which return value the application receives, which diagnostic records (SQLSTATE, native error number, text) are created, and what state the statement and connection are in afterward.

Key features

  • Success only with a matching shape: a 200 with unreadable or unexpected content isn't a success.
  • Database messages as over a direct connection: number, SQLSTATE, and text per message.
  • No invented results: a response that broke off or was truncated by the service isn't reported as complete.

Basic concepts

Classes of responses

ClassRecognized byReturn to the applicationDiagnostic recordState afterward
Data2xx, collection with value (reading) or columns (pass-through)SQL_SUCCESS; rows through SQLFetchnonecursor open
Change executed2xx on POST, PATCH, DELETESQL_SUCCESS, SQLRowCount = 1 (actions for tables without a key: the number stated)none–
Change hits no record404 or 412 on PATCH/DELETESQLRowCount = 0 – from this, Access shows its write conflictnone–
Second factor required401 with WWW-Authenticate: Wkl-Totpafter the code is entered, the result of the repeated request; without a dialog SQL_ERROR28000 with the service's message–
Identity to choose403 with X-Wkl-Rolesafter the choice, the result of the repeated request; without a dialog SQL_ERROR28000–
Sign-in refusedother 401 or 403SQL_ERROR28000, native number = HTTP status–
Database messages4xx with error.details whose code is a numberSQL_ERRORone record per message, at most 20: SQLSTATE from sqlState (if missing: 42000), native number = message number, text of the messagean open transaction stays open
Other rejection4xx without such messagesSQL_ERROR42000, native number = HTTP status, text from error.message or the first 200 characters of the body–
Result truncated"truncated": true in the pass-through response: the service's row limit took effectSQL_SUCCESS for the rows supplied, then SQL_ERROR on the next SQLFetchHY000 “The service cut the result off after N rows (the service's row limit); it is incomplete.” – the flag comes after the rows, so the driver can't know it any earlierthe rows supplied remain supplied; the statement ends
Redirect3xx with Locationwhen reading at the same origin: the result of the target address; otherwise SQL_ERROR08S01 with the target; the driver follows no redirect to another origin and doesn't repeat a redirected change–
Timeout504 or the driver's own time limitSQL_ERRORHYT00; not retried, because the service may still be workingresult of a change unknown
Service failure5xx except 504SQL_ERROR08S01, native number = HTTP status–
Transaction rolled back409 on commitSQL_ERROR from SQLEndTran40001nothing from the transaction saved
Connection droppedno responseafter a retry (see below), the result; otherwise SQL_ERROR08S01–
Certificate not trustedTLS errorSQL_ERROR, without a retry08S01 with the reason, for example “UntrustedRoot”–
Response unusable2xx with invalid JSON, without value or columns, with a value that doesn't match the announced type, or a stream that ends midwaySQL_ERROR08S01 with a message that names the defectthe statement ends with the error; rows already supplied remain supplied
Error in the driverany other exceptionSQL_ERRORHY000 “Unerwarteter Fehler: …” (Unexpected error: …); the complete exception is in the trace–

A response that has one of these shapes but carries one field more than expected counts as matching: the driver skips unknown fields and annotations. That keeps it compatible with later versions of a service, but has a consequence that's listed under Limits.

Why 08S01 for an unusable response. ODBC has no SQLSTATE of its own for “the peer isn't responding according to the protocol”. 08S01 (“Communication link failure”) tells the application what to do: the statement itself isn't wrong, the peer is; a retry with the same statement can succeed once the service responds correctly again. The message distinguishes this case from a network failure.

Warnings

ODBC reports a warning as SQL_SUCCESS_WITH_INFO with a diagnostic record of class 01. This driver generates warnings only itself:

SQLSTATEOccasion
01004a value was longer than the application's buffer and was returned truncated
01S02the application requested a cursor that the driver doesn't have; it continues forward-only without locks

Informational messages from the database on success don't reach the application. If the database sends a message with a successful statement (in SQL Server, for example PRINT or RAISERROR with severity up to 10), the application receives SQL_SUCCESS_WITH_INFO with this message through the SQL Server driver. Through this driver, SQL_SUCCESS arrives without it: the data service Wkl.Data.Gateway passes messages on only with a rejection, and the driver reads none in a successful response. An accompanying informational message with a rejection (SQLSTATE 01000), by contrast, appears as a further diagnostic record of the error.

Retry after a dropped connection

If the connection drops without a response, the driver retries after 1 and after 3 seconds: reads always, changes and custom statements read as a whole with the same Idempotency-Key. Not retried are an exceeded time limit, the commit of a transaction, and a streamed custom statement; with RETRY=OFF, nothing at all. When this is safe for which service is described under Commitments per kind of service.

Language of the messages

The text of a diagnostic record follows the display language of the Windows user the application runs as: German, Slovenian, or else English; so do the driver's dialogs. What counts is Windows, not a language that an application such as Office sets for itself. The SQLSTATE and the native error number are the same in every language – an application that evaluates errors checks those, not the text. Messages of the service and of the database are passed on unchanged, in the language they were written in there. The trace's own lines stay German; a diagnostic record appears there (DIAG) as the application received it. An application that reads messages narrow (SQLGetDiagRecA) receives them in its ANSI code page; Slovenian letters (č, š, ž) exist only in code page 1250 (Central European), the ANSI code page of a Slovenian Windows.

Limits

LimitConsequence
Only the first result set of a pass-through statement arrives row by rowfurther sets (results) are held in memory after the end of the first one; output values (outputs) are in the buffers as soon as SQLMoreResults reports SQL_NO_DATA, and right after execution for a statement without a result set
Informational messages from the database on success aren't passed onno SQL_SUCCESS_WITH_INFO
en/wiki/data-conectivity/odata-odbc/concepts/response-processing-and-diagnostics.txt · Last modified: by Wolfgang van der Stille