Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Usa questa guida con il driver ODBC 17 o 18 di Microsoft. Descrive il contratto diagnostico ODBC; non definisce mappature degli errori nativi specifiche della versione.
Una funzione ODBC restituisce un codice che descrive l'esito di quella chiamata. I registri diagnostici forniscono maggiori dettagli. L'interfaccia di programmazione applicativa (API) può riportare record dal Driver Manager, dal driver, dalla fonte dati o da più di un componente. Non considerare il codice di ritorno, SQLSTATE, il codice di errore nativo e il messaggio come intercambiabili.
Interpreta il codice di ritorno
Controlla il codice di ritorno prima di elaborare l'output o decidere se riprovare. Per SQL_ERROR e SQL_SUCCESS_WITH_INFO, recuperare la diagnostica dall'handle usato dalla funzione. Altri codici di ritorno possono avere anche record diagnostici quando il contratto di funzione lo consente.
| Codice restituito | Significato e risposta |
|---|---|
SQL_SUCCESS |
La funzione è stata completata correttamente. Controlla il contratto di output della funzione. |
SQL_SUCCESS_WITH_INFO |
La funzione si è conclusa con un avviso. Recupera ogni record diagnostico e verifica se l'output è completo, convertito o troncato. |
SQL_ERROR |
La funzione ha avuto esito negativo. Recupera ogni record diagnostico prima di chiamare un'altra funzione sullo stesso handle. |
SQL_INVALID_HANDLE |
La funzione rilevava un handle nullo o un handle di tipo sbagliato. ODBC non fornisce record diagnostici per questo codice di ritorno. Consulta il riferimento alla funzione per ulteriori requisiti di handle. |
SQL_NO_DATA |
Non sono disponibili altri dati per l'operazione. Controlla il riferimento alla funzione perché il significato e eventuali record di stato dipendono dalla funzione. |
Per ulteriori informazioni sul contratto completo di codici di ritorno, vedi codici ritorno ODBC.
Recupera ogni record diagnostico
Richiamare SQLGetDiagRec per i registri di stato a partire dal record numero 1. Continuare finché la funzione non restituisce SQL_NO_DATA, oppure leggi il conteggio dei record dal record di header 0 chiamando SQLGetDiagField con SQL_DIAG_NUMBER.
SQLGetDiagRec restituisce SQLSTATE di un record, il codice di errore nativo e il testo del messaggio. Usa SQLGetDiagField quando hai bisogno di altri campi di intestazione o di record.
Non fermarti dopo il primo record. Un componente ODBC può aggiungere un record di stato con informazioni sul proprio layer preservando le diagnostiche di un altro componente. L'ordine e il contenuto dei record possono aiutare a identificare dove è stato originato un errore.
Raccogli i record rapidamente. Una chiamata ODBC successiva che utilizza lo stesso handle sostituisce la sua area diagnostica, eccetto per le chiamate a SQLGetDiagRec, SQLGetDiagField, e la funzione legacy SQLError . Usa SQLGetDiagRec e SQLGetDiagField nel nuovo codice.
SQLGetDiagRec può restituire SQL_SUCCESS_WITH_INFO quando il suo buffer di messaggi è troppo piccolo. Il record è stato restituito, ma il testo del messaggio è stato troncato. Controlla la lunghezza del testo riportata e recupera il messaggio con un buffer più grande se ti serve il testo completo. Non confondere questo codice di ritorno da SQLGetDiagRec con quello della funzione ODBC originale.
Per ulteriori informazioni sul recupero diagnostico, vedi Record diagnostici, Using SQLGetDiagRec e SQLGetDiagField, e i riferimenti SQLGetDiagRec e SQLGetDiagField .
Raccogli i record diagnostici in C++
Usa questo helper C++11 con un handle ODBC esistente. Chiama SQLGetDiagRecW per raccogliere SQLSTATE, codice di errore nativo e testo dei messaggi Unicode in memoria senza registrare i messaggi.
#ifdef _WIN32
#include <windows.h>
#endif
#include <sql.h>
#include <sqlext.h>
#include <algorithm>
#include <limits>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
struct DiagnosticRecord {
std::string sqlstate;
SQLINTEGER native_error;
std::vector<SQLWCHAR> message;
bool message_truncated;
};
std::vector<DiagnosticRecord> ReadDiagnostics(SQLSMALLINT type, SQLHANDLE handle) {
const SQLSMALLINT limit = (std::numeric_limits<SQLSMALLINT>::max)();
std::vector<DiagnosticRecord> records;
for (SQLINTEGER number = 1; ; ++number) {
if (number > limit) {
throw std::runtime_error("Diagnostic record number exceeds SQLSMALLINT.");
}
SQLWCHAR state[6] = {};
SQLINTEGER native = 0;
std::vector<SQLWCHAR> message(256);
auto read = [&]() {
return SQLGetDiagRecW(type, handle, static_cast<SQLSMALLINT>(number),
state, &native, message.data(),
static_cast<SQLSMALLINT>(message.size()), nullptr);
};
SQLRETURN result = read();
if (result == SQL_NO_DATA) {
return records;
}
if (result == SQL_SUCCESS_WITH_INFO) {
message.resize(limit);
result = read(); // Retrieve the same record, not the next one.
}
if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
throw std::runtime_error("SQLGetDiagRecW couldn't retrieve a diagnostic record.");
}
message.erase(std::find(message.begin(), message.end(), SQLWCHAR{0}), message.end());
records.push_back({
std::string(state, state + 5),
native,
std::move(message),
result == SQL_SUCCESS_WITH_INFO
});
}
}
L'helper ritenta un messaggio troncato con la massima lunghezza positiva del buffer che SQLGetDiagRecW accetta. Se il messaggio non entra ancora, mantiene il testo disponibile e imposta message_truncated. Continua al record successivo invece di considerare quella troncatura come la fine della lista diagnostica. Genera un'eccezione se il recupero fallisce o se il numero di record supera l'intervallo SQLSMALLINT dell'API.
Ogni messaggio contiene SQLWCHAR unità di codice senza il terminatore nullo. Non considerarli come wchar_t, perché i tipi possono avere larghezze diverse. Convertili nella codifica del testo della tua applicazione quando devi elaborare o visualizzare il messaggio.
Chiama l'assistente immediatamente dopo l'operazione che restituisce un errore o un avviso. Questo frammento assume che statement sia un handle di istruzione valido e preparato e che l'esecuzione asincrona sia disabilitata:
#include <iostream>
SQLRETURN ExecuteWithDiagnostics(SQLHSTMT statement) {
SQLRETURN result = SQLExecute(statement);
if (result == SQL_ERROR || result == SQL_SUCCESS_WITH_INFO) {
const auto records = ReadDiagnostics(SQL_HANDLE_STMT, statement);
for (const auto& record : records) {
std::cerr << "SQLExecute: SQLSTATE=" << record.sqlstate
<< " native_error=" << record.native_error
<< " message_truncated=" << record.message_truncated << '\n';
}
} else if (result == SQL_INVALID_HANDLE) {
throw std::runtime_error("SQLExecute returned SQL_INVALID_HANDLE.");
}
return result;
}
Il wrapper conserva il codice di ritorno originale, incluso SQL_SUCCESS_WITH_INFO. Applica lo stesso schema ad altre chiamate ODBC, usando il tipo di handle e l'handle associati a quell'operazione. Gestisci altri codici di ritorno secondo il contratto di quella funzione.
L'output omette deliberatamente record.message. Se hai bisogno del testo del messaggio in un log, oscuralo secondo la politica dei dati della tua applicazione prima di scriverlo. L'helper non esegue la sanitizzazione dei messaggi conservati in memoria.
Leggi i campi diagnostici
I campi rispondono a diverse domande:
| Field | Cosa ti dice |
|---|---|
| SQLSTATE | Un codice di cinque caratteri che identifica una condizione diagnostica standardizzata. La sua classe è composta dai primi due caratteri. |
| Codice di errore nativo | Un valore specifico dell'origine dati o del componente ODBC. Non è un numero di errore universale, e non dovresti presumere che sia un numero di errore di SQL Server. |
| Testo del messaggio | Una spiegazione comprensibile dall'uomo. Interpretalo insieme a SQLSTATE e al codice di errore nativo; non analizzarlo come un contratto stabile e leggibile dalla macchina. |
Il Driver Manager, il driver e la sorgente dati possono generare ciascuno messaggi diagnostici. Un componente che aggiunge un record non deve sostituire o mascherare un errore o un avviso di un altro componente. Un codice di errore nativo potrebbe non essere disponibile o non avere un significato utile per una diagnostica generata da un componente. Per maggiori informazioni sulle regole relative ai componenti, vedi Regole per la gestione della diagnostica. Per maggiori informazioni sulle classi e i valori SQLSTATE, vedi SQLSTATEs.
Usa i record insieme al codice di ritorno della funzione e all'operazione. Ad esempio, SQL_SUCCESS_WITH_INFO significa che la funzione è completata, ma non garantisce che ogni valore di output sia completo. Un avviso di troncamento richiede di controllare la lunghezza restituita e decidere se recuperare i dati rimanenti. Per ulteriori informazioni, vedi lunghezza dei dati, lunghezza del buffer e troncamento.
Raccogliere prove attendibili
Per un caso di supporto, registra il nome della funzione, il tipo di handle, il codice di ritorno e ogni record diagnostico. Includi le versioni del driver e del Driver Manager, il sistema operativo, l'architettura e il tipo di origine dati. Oscurare credenziali, token di accesso, segreti della stringa di connessione, testo della query, valori dei parametri e dati personali o regolamentati prima di salvare o condividere l'output. I messaggi diagnostici e i trace log possono contenere dati applicativo.
Limita la traccia alla riproduzione più breve di cui hai bisogno. Memorizza i log in una directory accessibile solo all'account che esegue l'applicazione e utilizza un percorso di log esplicito invece di un default condiviso o temporaneo. Smetti di tracciare quando la riproduzione termina, poi rimuovi il file di traccia quando non ne hai più bisogno.
Scegli il layer di tracciamento
La diagnostica e il tracciamento applicativo rispondono a diverse domande:
| Livello | Cosa acquisisce | Usalo per |
|---|---|---|
| Diagnostica applicazioni | Codici di ritorno e record diagnostici da singole chiamate ODBC | Identificare la funzione che ha fallito o restituito un avviso e preservare tutti i suoi campi diagnostici. |
| Traccia ODBC Driver Manager | Chiamate API ODBC tra l'applicazione, il Driver Manager e il driver | Vedi quali chiamate ha fatto l'applicazione e quali codici di ritorno sono stati restituiti. Gli argomenti di traccia possono esporre valori sensibili. |
| Traccia specifica per il driver | Eventi interni del driver, quando il driver documenta un controllo supportato | Indaga sul comportamento dei driver che una traccia API non può mostrare. Non dare per scontato che un tracciamento Driver Manager consenta questa funzione. |
Su Windows, ODBC Driver Manager supporta il tracciamento attraverso la scheda Tracing in ODBC Data Source Administrator e gli attributi SQL_ATTR_TRACE e SQL_ATTR_TRACEFILE. Per impostazione predefinita, il tracciamento è per utente. Il tracciamento a livello di macchina richiede permessi amministratori locali e può catturare le chiamate da applicazioni che girano con altre identità locali. Preferisci il tracciamento per utente e fermalo non appena termina la riproduzione del problema. Per maggiori informazioni, consulta Opzioni di tracciamento impostate, Abilitazione del tracciamento e SQLSetConnectAttr.
Su Linux e macOS, vedi Data access tracing con il driver ODBC su Linux e macOS per la configurazione di unixODBC Driver Manager.
Le attuali linee guida di programmazione Linux e macOS mantengono una dichiarazione storica secondo cui il tracciamento integrato della diagnostica (BID) non è stato verificato prima del driver ODBC 17.3. Quella nota non descrive un attuale controllo di traccia specifico del driver. La procedura unixODBC cattura le chiamate API del Driver Manager, non gli eventi BID.