OCI編程基礎篇(五) 處理錯誤信息
訪問www.tomcoding.com網站,學習Oracle內部數據結構,詳細文檔說明,下載Oracle的exp/imp,DUL,logminer,ASM工具的源代碼,學習高技術含量的內容。
前面我們看到了連接數據庫的過程,調用OCI函數的過程中可能出現錯誤,那么怎樣得到出錯的信息呢?我們平時看到的ORA-XXXXX等錯誤都有詳細的信息,好讓我們來診斷錯誤的原因,下面就來看看怎樣處理這些錯誤。
我們在創建完OCI環境句柄后,第一個分配的句柄就是錯誤句柄,以后的每個OCI函數調用時都會把這個句柄傳給函數,在函數執行過程中如果遇到錯誤,就會把錯誤碼和錯誤信息與這個句柄關聯起來,調用返回錯誤后,就可以利用這個句柄得到特定的錯誤碼和詳細的錯誤信息。
通過錯誤句柄得到錯誤信息需要一個函數,叫做OCIErrorGet(),函數原型和參數如下。
sword OCIErrorGet ( void *hndlp,
ub4 recordno,
OraText *sqlstate,
sb4 *errcodep,
OraText *bufp,
ub4 bufsiz,
ub4 type );
hndlp是一個輸入參數,指定從哪個句柄提取錯誤信息,一般都是錯誤句柄,有些函數沒有傳入錯誤句柄的,比如OCIHandleAlloc(),只傳入了環境句柄,那么這兒的參數就是環境句柄。
recordno是一個輸入參數,指定錯誤記錄號,也就是提取哪個錯誤的信息,一般賦值為1,提取第一個錯誤。
sqlstate是一個輸出參數,這個參數已經作廢了。
errcodep是一個輸出參數,返回一個錯誤碼,就是ORA-XXXXX后面的XXXXX。
bufp是一個輸出參數,返回出錯的消息文本。
bufsiz是一個輸入參數,指示存放出錯消息的緩沖區bufp的大小。如果太小的緩沖區,錯誤消息文本會被截斷,而且還會報錯。
type是一個輸入參數,指示傳入的句柄是錯誤句柄還是環境句柄,一般為錯誤句柄。
舉一個例子,比如前面連接數據庫時,建立服務器句柄與數據庫的通信路徑出現錯誤,用下面的代碼取得錯誤信息。
/* 定義錯誤碼和錯誤信息 */
int ec;
char errbuf[512];
rc = OCIServerAttach(
svrhp,
errhp,
(CONST text *)NULL,
0,
OCI_DEFAULT
);
if (rc != OCI_SUCCESS) {
OCIErrorGet(errhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR);
fprintf(stderr, "OCIServerAttach() - [%d] %s\n", ec, errbuf);
return (-1);
}
下面我們寫一個函數來處理OCI函數的返回值,這樣就不用每次都處理錯誤了,在這個函數中一次處理完畢。
/* 定義兩個全局變量,一個返回錯誤碼,一個返回錯誤信息文本 */ int oci_errcode; char oci_errmsg[16384]; int check_oci_error(OCIError *errhp, sword status){ sb4 ec; oci_errcode = 0; switch (status) { /* 調用函數成功 */ case OCI_SUCCESS: /* 需要提供進一步的數據,留待調用邏輯處理 */ case OCI_NEED_DATA: /* 查詢后沒有數據返回,留待調用邏輯處理 */ case OCI_NO_DATA: return (status); case OCI_ERROR: if (OCIErrorGet((void *)errhp, (ub4)1, (OraText *)NULL, &ec, (OraText *)oci_errmsg, 16383, OCI_HTYPE_ERROR) != OCI_SUCCESS) { oci_errcode = -1; fprintf(stderr, "need bigger buffer for error message.\n"); return (-1); } oci_errcode = ec; oci_errmsg[16383] = '\0'; fprintf(stderr, "Error - [%d] %s\n", oci_errcode, oci_errmsg); return (status); case OCI_SUCCESS_WITH_INFO: if (OCIErrorGet((void *)errhp, (ub4)1, (OraText *)NULL, &ec, (OraText *)oci_errmsg, 16383, OCI_HTYPE_ERROR) != OCI_SUCCESS) { oci_errcode = -1; fprintf(stderr, "need bigger buffer for error message.\n"); return (-1); } oci_errcode = ec; oci_errmsg[16383] = '\0'; fprintf(stderr, "Warning - [%d] %s\n", oci_errcode, oci_errmsg); return (status); case OCI_INVALID_HANDLE: oci_errcode = -1; sprintf(oci_errmsg, "Error - OCI_INVALID_HANDLE"); fprintf(stderr, "Error - OCI_INVALID_HANDLE\n"); break; case OCI_STILL_EXECUTING: oci_errcode = -1; sprintf(oci_errmsg, "Error - OCI_STILL_EXECUTING"); fprintf(stderr, "Error - OCI_STILL_EXECUTING\n"); break; case OCI_CONTINUE: oci_errcode = -1; sprintf(oci_errmsg, "Error - OCI_CONTINUE"); fprintf(stderr, "Error - OCI_CONTINUE\n"); break; default: oci_errcode = -1; sprintf(oci_errmsg, "Error - [%d] Unknow OCI error", status); fprintf(stderr, "Error - [%d] Unknow OCI error\n", status); } return (-1); }
使用上面的函數我們改寫一下連接數據庫中,建立服務器句柄與數據庫通信路徑出錯的情況。
if (check_oci_error(errhp, OCIServerAttach(
svrhp,
errhp,
(CONST text *)NULL,
0,
OCI_DEFAULT
)) < 0) return (-1);
這樣看起來是不是簡潔多了。

浙公網安備 33010602011771號