诊断和错误处置
前往码
每当挪用 CLI/ODBC 函数时,都会将一个特别的值,即所谓的前往码,前往给挪用的使用次序,以诠释函数可否按预期执行。倘若由于某种缘故原由函数没有告成执行,那么生成的前往码的值将指示函数失败的缘故原由。CLI/ODBC 函数可曩昔往的前往码如表 2 所示:
表 2. CLI/ODBC 函数前往码
前往码
意义
SQL_SUCCESS
CLI/ODBC 函数告成完成
SQL_SUCCESS_WITH_INFO
CLI/ODBC 函数告成完成,可是遇到一个告诫或非致命错误
SQL_NO_DATA
or SQL_NO_DATA_FOUND
CLI/ODBC 函数告成完成,可是未找到相关的数据
SQL_INVALID_HANDLE
由于指定了无效的状态句柄、毗邻句柄、语句句柄或描写符句柄,CLI/ODBC 函数失败。只需在指定的句柄还没有分派空间,年夜要类型错误的状态下(比方,当祈望的是一个状态句柄时,供给的却是一个毗邻句柄),才会前往该前往码
SQL_NEED_DATA
由于函数没有找到祈望在执行时运用的数据,CLI/ODBC 函数失败。当前往该前往码时,平但凡由于参数或列已经被绑定为及时数据的(SQL_DATA_AT_EXEC
)参数/列
SQL_STILL_EXECUTING
异步启动的 CLI/ODBC 函数模仿还是在执行
SQL_ERROR
CLI/ODBC 函数失败
错误处置是使用次序中严重的一部门,CLI/ODBC 使用次序也不例外。CLI/ODBC 使用次序至少应该经过反省前往码来确认 CLI/ODBC 函数可否告成执行。当一个函数未能按预期执行时,应该报告用户出现了错误或告诫,并尽可以向用户供给有助于他们快速发明并修复标题的诊断信息。
回页首
SQLSTATE
虽然前往码可以报告使用次序可否遇到错误或告诫,可是它不能为使用次序供给关于是什么招致错误或告诫出现的具体信息。由于在处置一个标题时,平凡还须要关于一个错误或告诫的更多信息,因此 DB2 (以及其他关连数据库产物)运用一组错误消息码,即所谓的 SQLSTATE 来供给告诫和错误的填补诊断信息。SQLSTATE 是由字母和数字构成的一个字符串,长度为 5 个字符(字节),样式为 ccsss,其中 cc 透露发扬分析错误消息的类型,sss 透露发扬分析错误消息的子类。类型为 01
的 SQLSTATE 对应于一个告诫;类型为 HY
的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM
的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于差其余数据库处事器平凡有差其余诊断消息码,因此 SQLSTATE 遵命 X/Open CLI 标准标准中列出的标准。SQLSTATE 值的标准化使得使用次序开发人员关于差异关连数据库产物可以按分例如的方式处置错误和告诫。)
与前往码差异,SQLSTATE 平凡被当作引导信息,并且不须要经过驱动次序来前往它们。因此,虽然驱动次序应该老是前往精确的 SQLSTATE 以指示它们所能检测的错误或告诫,可是使用次序不该老是指望它。由于 SQLSTATE 并不是必定会前往,因此年夜多半使用次序只是将 SQLSTATE 与响应的诊断消息和可用确本地错误代码一路前往给用户。
回页首
获取诊断信息
那么,当 CLI/ODBC 函数未能精确执行时,怎样获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以经过挪用 SQLGetDiagRec()
函数、SQLGetDiagField()
函数或同时挪用这两个函数获得。这两个函数担当状态句柄、毗邻句柄、语句句柄或描写符句柄作为输入,然后前往关于近来运用指定句柄执行的 CLI/ODBC 函数的诊断信息。倘若生成了多个诊断记实,那么使用次序必须重复地挪用这两个函数中的一个函数或同时挪用这两个函数,直到获得所有可用的诊断信息。(经过挪用 SQLGetDiagField()
函数,并指定记实号 0
—— header 记实号 —— 和 SQL_DIAG_NUMBER
选项,可以确定可用的诊断信息的总数。)
诊断信息以诊断记实的方式存储在内容中。使用次序可以经过挪用 SQLGetDiagRec()
函数间接获得 SQLSTATE 值、诊断消息和本地错误代码。可是,不能运用该函数从诊断 header 记实中检索信息。使用次序必须运用 SQLGetDiagField()
函数来检索诊断 header 记实中存储的信息。SQLGetDiagField()
函数还可以用于获取单个诊断记实字段的值。(比方,SQLGetDiagField()
函数可用于获得关于受 select、insert、update 或 delete 行使影响的行数的信息。)
回页首
一个诊断/错误处置的例子
后面已经引见了,当出现错误或告诫时,怎样运用前往码防止检测,以及怎样运用诊断记实供给反响。 接上去,让我们看一看 CLI/ODBC 使用次序中平但凡怎样防止错误处置和检索诊断信息的。下面这个 CLI/ODBC 使用次序是用 C 言语编写的,它展现了当出现错误年夜要须要更多关于与一个 SELECT
SQL 语句相接洽关系的处置的信息时,怎样运用 SQLGetDiagRec()
和 SQLGetDiagField()
函数显示诊断信息。
清单 4. 运用 SQLGetDiagField() 和 SQLGetDiagRec() 函数
#include <stdio.h> #include <string.h> #include <sqlcli1.h> int main() { // Declare The Local Memory Variables SQLHANDLE EnvHandle = 0; SQLHANDLE ConHandle = 0; SQLHANDLE StmtHandle = 0; SQLCHAR ConString[512]; SQLRETURN RetCode = SQL_SUCCESS; SQLSMALLINT Counter = 0; SQLINTEGER NumRecords = 0; SQLINTEGER NativeErr = 0; SQLCHAR SQLState[6]; SQLCHAR ErrMsg[255]; SQLSMALLINT ErrMsgLen = 0; SQLCHAR SQLStmt[255]; // Allocate An Environment Handle SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &EnvHandle); // Set The ODBC 使用次序 Version To 3.x if (EnvHandle != 0) SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER); // Allocate A Connection Handle if (EnvHandle != 0) SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle, &ConHandle); // Build A Valid Connection String sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};"); strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2"); // Connect To The Appropriate Data Source if (ConHandle != 0) RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT); // If Unable To Establish A Data Source Connection, // Obtain Any Diagnostic Information Available if (RetCode != SQL_SUCCESS) { // Find Out How Many Diagnostic Records Are // Available SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0, SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER, NULL); // Retrieve And Display The Diagnostic Information // Produced for (Counter = 1; Counter <= NumRecords; Counter ) { // Retrieve The Information Stored In Each // Diagnostic Record Generated SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter, SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg), &ErrMsgLen); // Display The Information Retrieved printf("SQLSTATE : %s\n", SQLState); printf("%s\n", ErrMsg); // Prepare To Exit goto EXIT; } } // Allocate An SQL Statement Handle if (ConHandle != 0) SQLAllocHandle(SQL_HANDLE_STMT, ConHandle, &StmtHandle); // Set The Appropriate Statement Attributes SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0); SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER) SQL_CURSOR_STATIC, 0); // Define A SELECT SQL Statement strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM "); strcat((char *) SQLStmt, "department"); // Prepare The SQL Statement if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS) { // Obtain The Estimated Number Of Rows That Will Be // Returned By The SELECT Statement RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, SQL_IS_INTEGER, NULL); // Display The Information Retrieved if (RetCode == SQL_SUCCESS) printf("Estimated number of records that will be returned : %d\n", NumRecords); // Execute The SELECT SQL Statement SQLExecute(StmtHandle); // Obtain The Actual Number Of Rows Returned By // The SELECT Statement RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, SQL_IS_INTEGER, NULL); // Display The Information Retrieved if (RetCode == SQL_SUCCESS) printf("Actual number of records returned : %d\n", NumRecords); } EXIT: // Free The SQL Statement Handle if (StmtHandle != 0) SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle); // Free The Connection Handle if (ConHandle != 0) SQLFreeHandle(SQL_HANDLE_DBC, ConHandle); // Free The Environment Handle if (EnvHandle != 0) SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle); // Return Control To The Operating System return(0); }
版权声明: 原创作品,准许转载,转载时请务必以超链接方式标明文章 原始理由 、作者信息和本声明。否则将清查执法责任。