unxiODBC编程(五)错误处理
ODBC的每个函数调用完毕都会返回一个SQLRETURN类型的返回码,这个类型其实是短整数(short int)类型,是一个16位的整数。返回值一共有下面几个值。
1. SQL_SUCCESS,表示函数执行成功。
2. SQL_SUCCESS_WITH_INFO,表示函数执行成功,但是返回了警告信息。比如连接数据库时返回密码即将过期信息。
3. SQL_STILL_EXECUTING,表示调用函数时,前一个SQL语句还在执行。
4. SQL_NEED_DATA,表示调用函数后,有动态数据需要提供。
5. SQL_NO_DATA,表示调用函数后,没有数据返回。最典型的就是从结果集中Fetch数据时,取走最后一条数据后没有其他数据了,返回SQL_NO_DATA。
6. SQL_ERROR,表示调用函数后,出现了错误。需要调用诊断函数获取错误信息。
7. SQL_INVALID_HANDLE,表示调用函数时,传入了无效的句柄。
当调用的函数返回SQL_SUCCESS_WITH_INFO或SQL_ERROR时,可以调用SQLGetDiagRec()函数来返回错误信息,下面看看函数的原型和参数。
SQLRETURN SQLGetDiagRec(
SQLSMALLINT HandleType,
SQLHANDLE Handle,
SQLSMALLINT RecNumber,
SQLCHAR * SQLState,
SQLINTEGER * NativeErrorPtr,
SQLCHAR * MessageText,
SQLSMALLINT BufferLength,
SQLSMALLINT * TextLengthPtr);
HandleType是一个输入参数,是出错函数传入的句柄的类型。
Handle是一个输入参数,是出错函数传入的句柄。
RecNumber是一个输入参数,指示诊断记录的编号。记录从 1 开始编号。
SQLState是一个输出参数,返回状态码,该缓冲区将返回一个五个字符的 SQLSTATE 代码。
NativeErrorPtr是一个输出参数,返回错误码,该缓冲区将返回特定于数据源的本机错误代码。比如数据源是一个使用Oracle驱动程序的配置项,那么返回的就是Oracle的出错码。
MessageText是一个输出参数,指向返回诊断消息文本字符串的缓冲区的指针。用于存放出错信息。
BufferLength是一个输入参数,MessageText 缓冲区的长度(以字符为单位)。如果过小诊断函数会返回错误。
TextLengthPtr是一个输出参数,返回信息文本的总字符数。
看一个例子,连接数据库出错时,怎样处理错误。
SQLSMALLINT i;
SQLRETURN rc;
SQLINTEGER ecode;
SQLSMALLINT alen;
WCHAR msgtxt[8192];
WCHAR state[SQL_SQLSTATE_SIZE+1];
rc = SQLConnect(dbch, (SQLCHAR *)ds_name, SQL_NTS, (SQLCHAR *)usrname, SQL_NTS, (SQLCHAR *)passwd, SQL_NTS);
if ((rc == SQL_ERROR) || (rc == SQL_SUCCESS_WITH_INFO)) {
for (i=1; ; i++) {
rc = SQLGetDiagRec(SQL_HANDLE_DBC, dbch, i, (SQLCHAR *)state, &ecode,
(SQLCHAR *)msgtxt, (SQLSMALLINT)(sizeof(msgtxt) / sizeof(WCHAR)),
(SQLSMALLINT *)&alen);
if (rc == SQL_SUCCESS) {
fprintf(stderr, "ERROR: [%s] [%d] - %s\n", (char *)state, ecode, (char *)msgtxt);
} else if (rc == SQL_NO_DATA)
break;
else {
fprintf(stderr, "get diagnostic record error.\n");
break;
}
}
}
我们可以写一个函数来处理调用函数返回的结果。代码如下。
/*
* hndl - 出错函数输入的句柄
* htype - 出错函数输入的句柄类型
* rc - 出错函数的返回码
*/
SQLRETURN check_odbc_error(SQLHANDLE hndl, SQLSMALLINT htype, SQLRETURN rc)
{
SQLRETURN ret;
SQLSMALLINT irec;
SQLSMALLINT alen;
SQLINTEGER ecode;
WCHAR msgtxt[8192];
WCHAR state[SQL_SQLSTATE_SIZE+1];
switch (rc) {
/* 函数返回成功,需要动态数据,没有数据了,直接返回原始码,不用处理错误 */
case SQL_SUCCESS:
case SQL_NEED_DATA:
case SQL_NO_DATA:
return (rc);
/* 无效句柄 */
case SQL_INVALID_HANDLE:
fprintf(stderr, "Invalid handle!\n"):
return (rc);
/* 返回成功但有警告信息或者出错,处理错误记录 */
case SQL_SUCCESS_WITH_INFO:
case SQL_ERROR:
/* 从1开始取回每一条出错记录信息 */
for (irec=1; ; irec++) {
ret = SQLGetDiagRec(htype, hndl, irec, (SQLCHAR *)state, &ecode,
(SQLCHAR *)msgtxt, (SQLSMALLINT)(sizeof(msgtxt) / sizeof(WCHAR)),
(SQLSMALLINT *)&alen);
if (ret == SQL_NO_DATA)
break;
if (ret == SQL_SUCCESS) {
fprintf(stderr,"[%s] %d - %s\n",
(char *)state, ecode, (char *)msgtxt);
} else {
fprintf(stderr, "Get diagnostic message error!\n");
break;
}
}
return (rc);
}
return (0);
}
后面可以使用上面的函数来处理调用函数的返回码,简单实用,比如调用执行语句函数。
rc = SQLExecute(stmth);
check_odbc_error(stmth, SQL_HANDLE_STMT, rc);
如果你想看一些有关数据库的高技术含量的源代码和文档,请访问www.tomcoding.com网站。