前面我们看到了连接数据库的过程,调用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);
这样看起来是不是简洁多了。