兩個 ODBC 函數調用可用來擷取 ODBC 訊息: SQLGetDiagRec 和 SQLGetDiagField。 若要取得 SQLState、 pfNative 和 ErrorMessage 診斷欄位中的主要 ODBC 相關信息,請呼叫 SQLGetDiagRec ,直到傳回SQL_NO_DATA為止。 針對每個診斷記錄,可以呼叫 SQLGetDiagField 來擷取個別欄位。 所有驅動程式特定欄位都必須使用 SQLGetDiagField來擷取。
SQLGetDiagRec 和 SQLGetDiagField 是由 ODBC 驅動程式管理員處理,而不是個別驅動程式。 ODBC 驅動程式管理員在成功連線之前,不會快取驅動程式特定的診斷字段。 在成功連線之前,無法呼叫驅動程式特定診斷欄位的 SQLGetDiagField 。 這包括 ODBC 連接命令,即使它們傳回SQL_SUCCESS_WITH_INFO也一樣。 除非下一個 ODBC 函數調用,才能使用驅動程式特定的診斷欄位。
範例
說明
此範例示範呼叫 SQLGetDiagRec 以取得標準 ODBC 資訊的簡單錯誤處理程式。 然後它會測試有效的連線,如果存在,則會呼叫 SQLGetDiagField SQL Server ODBC 驅動程式特定的診斷字段。 IA64 不支援此範例。
此範例是針對 ODBC 3.0 版或更新版本所開發。
這很重要
盡可能使用 Windows 驗證。 如果 Windows 驗證無法使用,請提示使用者在運行時間輸入其認證。 避免將認證儲存在檔案中。 如果您必須保存認證,您應該使用 Win32 加密 API 來加密認證。
您將需要名為 AdventureWorks 的 ODBC 數據源,其預設資料庫是 AdventureWorks 範例資料庫。 (您可以從 Microsoft SQL Server 範例和社群專案 首頁下載 AdventureWorks 範例資料庫。此數據源必須以作系統提供的 ODBC 驅動程式為基礎(驅動程式名稱為 “SQL Server” )。 如果您要在 64 位作系統上建置並執行此範例作為 32 位應用程式,您必須在 %windir%\SysWOW64\odbcad32.exe中使用 ODBC 系統管理員建立 ODBC 數據來源。
此範例會連線到計算機的預設 SQL Server 實例。 若要連線到具名實例,請變更 ODBC 數據源的定義,以使用下列格式指定實例:伺服器\namedinstance。 根據預設,SQL Server Express 會安裝至具名實例。
執行第一個 (Transact-SQL) 程式代碼清單,以建立此範例所使用的預存程式。
使用 odbc32.lib 編譯第二個 (C++) 程式代碼清單。 然後,執行程式。
執行第三個 (Transact-SQL) 程式代碼清單,以刪除此範例所使用的預存程式。
程式碼
use AdventureWorks
IF EXISTS (SELECT name FROM sysobjects WHERE name = 'BadOne')
DROP PROCEDURE BadOne
Go
CREATE PROCEDURE BadOne
AS
SELECT * FROM Purchasing.Vendor
Go
程式碼
// compile with: odbc32.lib
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <odbcss.h>
#define MAXBUFLEN 256
SQLHENV henv = SQL_NULL_HENV;
SQLHDBC hdbc1 = SQL_NULL_HDBC;
SQLHSTMT hstmt1 = SQL_NULL_HSTMT;
void ProcessLogMessages(SQLSMALLINT plm_handle_type, SQLHANDLE plm_handle, char *logstring, int ConnInd);
void Cleanup() {
if (hstmt1 != SQL_NULL_HSTMT)
SQLFreeHandle(SQL_HANDLE_STMT, hstmt1);
if (hdbc1 != SQL_NULL_HDBC) {
SQLDisconnect(hdbc1);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
}
if (henv != SQL_NULL_HENV)
SQLFreeHandle(SQL_HANDLE_ENV, henv);
}
int main() {
RETCODE retcode;
// Allocate the ODBC environment and save handle.
retcode = SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv);
if ( (retcode != SQL_SUCCESS_WITH_INFO) && (retcode != SQL_SUCCESS)) {
printf("SQLAllocHandle(Env) Failed\n\n");
Cleanup();
return(9);
}
// Notify ODBC that this is an ODBC 3.0 app.
retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, SQL_IS_INTEGER);
if ( (retcode != SQL_SUCCESS_WITH_INFO) && (retcode != SQL_SUCCESS)) {
printf("SQLSetEnvAttr(ODBC version) Failed\n\n");
Cleanup();
return(9);
}
// Allocate ODBC connection handle and connect.
retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc1);
if ( (retcode != SQL_SUCCESS_WITH_INFO) && (retcode != SQL_SUCCESS)) {
printf("SQLAllocHandle(hdbc1) Failed\n\n");
Cleanup();
return(9);
}
// This sample use Integrated Security. Please create the SQL Server
// DSN by using the Windows NT authentication.
retcode = SQLConnect(hdbc1, (UCHAR*)"AdventureWorks", SQL_NTS, (UCHAR*)"",SQL_NTS, (UCHAR*)"", SQL_NTS);
if ( (retcode != SQL_SUCCESS) &&
(retcode != SQL_SUCCESS_WITH_INFO) ) {
ProcessLogMessages(SQL_HANDLE_DBC, hdbc1, "SQLConnect() Failed\n\n", FALSE);
Cleanup();
return(9);
}
else {
ProcessLogMessages(SQL_HANDLE_DBC, hdbc1,
"\nConnect Successful\n\n", FALSE);
}
// Allocate statement handle, and then execute command.
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt1);
if ( (retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO) ) {
ProcessLogMessages(SQL_HANDLE_DBC, hdbc1, "SQLAllocHandle(hstmt1) Failed\n\n", TRUE);
Cleanup();
return(9);
}
retcode = SQLExecDirect(hstmt1, (UCHAR*)"exec BadOne", SQL_NTS);
if ( (retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO) ) {
ProcessLogMessages(SQL_HANDLE_STMT, hstmt1, "SQLExecute() Failed\n\n", TRUE);
Cleanup();
return(9);
}
// Clear any result sets generated.
while ( ( retcode = SQLMoreResults(hstmt1) ) != SQL_NO_DATA )
;
// Clean up.
SQLFreeHandle(SQL_HANDLE_STMT, hstmt1);
SQLDisconnect(hdbc1);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
}
void ProcessLogMessages(SQLSMALLINT plm_handle_type, SQLHANDLE plm_handle, char *logstring, int ConnInd) {
RETCODE plm_retcode = SQL_SUCCESS;
UCHAR plm_szSqlState[MAXBUFLEN] = "", plm_szErrorMsg[MAXBUFLEN] = "";
SDWORD plm_pfNativeError = 0L;
SWORD plm_pcbErrorMsg = 0;
SQLSMALLINT plm_cRecNmbr = 1;
SDWORD plm_SS_MsgState = 0, plm_SS_Severity = 0;
SQLINTEGER plm_Rownumber = 0;
USHORT plm_SS_Line;
SQLSMALLINT plm_cbSS_Procname, plm_cbSS_Srvname;
SQLCHAR plm_SS_Procname[MAXNAME], plm_SS_Srvname[MAXNAME];
if (logstring)
printf(logstring);
while (plm_retcode != SQL_NO_DATA_FOUND) {
plm_retcode = SQLGetDiagRec(plm_handle_type, plm_handle, plm_cRecNmbr,
plm_szSqlState, &plm_pfNativeError, plm_szErrorMsg,
MAXBUFLEN - 1, &plm_pcbErrorMsg);
// Note that if the application has not yet made a successful connection,
// the SQLGetDiagField information has not yet been cached by ODBC Driver Manager and
// these calls to SQLGetDiagField will fail.
if (plm_retcode != SQL_NO_DATA_FOUND) {
if (ConnInd) {
plm_retcode = SQLGetDiagField( plm_handle_type, plm_handle, plm_cRecNmbr,
SQL_DIAG_ROW_NUMBER, &plm_Rownumber,
SQL_IS_INTEGER, NULL);
plm_retcode = SQLGetDiagField( plm_handle_type, plm_handle, plm_cRecNmbr,
SQL_DIAG_SS_LINE, &plm_SS_Line, SQL_IS_INTEGER, NULL);
plm_retcode = SQLGetDiagField( plm_handle_type, plm_handle, plm_cRecNmbr,
SQL_DIAG_SS_MSGSTATE, &plm_SS_MsgState,
SQL_IS_INTEGER, NULL);
plm_retcode = SQLGetDiagField( plm_handle_type, plm_handle, plm_cRecNmbr,
SQL_DIAG_SS_SEVERITY, &plm_SS_Severity,
SQL_IS_INTEGER, NULL);
plm_retcode = SQLGetDiagField( plm_handle_type, plm_handle, plm_cRecNmbr,
SQL_DIAG_SS_PROCNAME, &plm_SS_Procname,
sizeof(plm_SS_Procname), &plm_cbSS_Procname);
plm_retcode = SQLGetDiagField( plm_handle_type, plm_handle, plm_cRecNmbr,
SQL_DIAG_SS_SRVNAME, &plm_SS_Srvname,
sizeof(plm_SS_Srvname), &plm_cbSS_Srvname);
}
printf("szSqlState = %s\n", plm_szSqlState);
printf("pfNativeError = %d\n", plm_pfNativeError);
printf("szErrorMsg = %s\n", plm_szErrorMsg);
printf("pcbErrorMsg = %d\n\n", plm_pcbErrorMsg);
if (ConnInd) {
printf("ODBCRowNumber = %d\n", plm_Rownumber);
printf("SSrvrLine = %d\n", plm_Rownumber);
printf("SSrvrMsgState = %d\n", plm_SS_MsgState);
printf("SSrvrSeverity = %d\n", plm_SS_Severity);
printf("SSrvrProcname = %s\n", plm_SS_Procname);
printf("SSrvrSrvname = %s\n\n", plm_SS_Srvname);
}
}
plm_cRecNmbr++; // Increment to next diagnostic record.
}
}
程式碼
use AdventureWorks
DROP PROCEDURE BadOne
GO