c++ - 我可以在出错后使用 ODBC 语句吗(是否有效)?

标签 c++ sql odbc

在使用它的命令(例如 SQLExecute)失败后,我能否再次使用 ODBC 语句句柄(即它是否有效)? (不返回 SQL_SUCCESS 或 SQL_SUCCESS_WITH_INFO)

这可能是特定于 DBMS/驱动程序的吗?

我在 ODBC Programmer's reference 上找不到任何相关信息页面。

最佳答案

我也没有在文档中找到任何权威答案。但我会说:是的 - 你可以,除了返回的错误代码是 SQL_INVALID_HANDLE:

推理:

  1. 需要语句句柄作为参数的函数的文档均未提及任何有关在出现错误时句柄无效的内容。重要的是返回码。因此,如果没有明确禁止,它应该可以工作。

  2. 如果返回 SQL_ERROR,您可以使用相同的语句句柄来获取有关该错误的更多信息。所以语句句柄仍然有一个有效的上下文。

    3:我们一次又一次地使用相同的语句,即使在返回 SQL_ERROR 的情况下也是如此。到目前为止我们没有遇到任何问题。好吧,但大多数情况下我们不会收到任何错误..

更新,在关于“语句已终止”的评论之后:是的,您可以重新使用相同的语句句柄。该错误只是表明当前运行的语句已被服务器终止。请参阅以下示例,它会产生这样的错误,然后再次使用相同的语句来成功插入:

#include <windows.h>
#include <tchar.h>
#include <iostream>
#include <sql.h>
#include <sqlext.h>
#include <sqlucode.h>

void printErr(SQLHANDLE handle, SQLSMALLINT handleType)
{
    SQLSMALLINT recNr = 1;
    SQLRETURN ret = SQL_SUCCESS;
    while (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
    {
        SQLWCHAR errMsg[SQL_MAX_MESSAGE_LENGTH + 1];
        SQLWCHAR sqlState[5 + 1];
        errMsg[0] = 0;
        SQLINTEGER nativeError;
        SQLSMALLINT cb = 0;
        ret = SQLGetDiagRec(handleType, handle, recNr, sqlState, &nativeError, errMsg, SQL_MAX_MESSAGE_LENGTH + 1, &cb);
        if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
        {
            std::wcerr << L"ERROR; native: " << nativeError << L"; state: " << sqlState << L"; msg: " << errMsg << std::endl;
        }
        ++recNr;
    }
}


int _tmain(int argc, _TCHAR* argv[])
{
    // connect to db
    SQLRETURN   nResult = 0;
    SQLHANDLE   handleEnv = 0;

    nResult = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, (SQLHANDLE*)&handleEnv);
    nResult = SQLSetEnvAttr(handleEnv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3_80, SQL_IS_INTEGER);

    SQLHANDLE   handleDBC = 0;
    nResult = SQLAllocHandle(SQL_HANDLE_DBC, handleEnv, (SQLHANDLE*)&handleDBC);

    SQLWCHAR     strConnect[256] = L"Driver={SQL Server};Server=.\\INSTANCE;Database=Test;Trusted_Connection=yes;";
    SQLWCHAR     strConnectOut[1024] = { 0 };
    SQLSMALLINT nNumOut = 0;
    nResult = SQLDriverConnect(handleDBC, NULL, (SQLWCHAR*)strConnect, SQL_NTS, (SQLWCHAR*)strConnectOut, sizeof(strConnectOut), &nNumOut, SQL_DRIVER_NOPROMPT);
    if (!SQL_SUCCEEDED(nResult))
        printErr(handleDBC, SQL_HANDLE_DBC);

    SQLHSTMT    handleStatement = SQL_NULL_HSTMT;
    nResult = SQLAllocHandle(SQL_HANDLE_STMT, handleDBC, (SQLHANDLE*)&handleStatement);
    if (!SQL_SUCCEEDED(nResult))
        printErr(handleDBC, SQL_HANDLE_DBC);

    // try to drop table Wallet, ignore if it exists
    nResult = SQLExecDirect(handleStatement, L"DROP TABLE Wallet", SQL_NTS);

    // create table Wallet
    nResult = SQLExecDirect(handleStatement, L"CREATE TABLE Wallet (WalletID int NOT NULL,  Name nvarchar(5) NOT NULL)", SQL_NTS);
    if (!SQL_SUCCEEDED(nResult))
            printErr(handleStatement, SQL_HANDLE_STMT);

    // Create a query that fails with data truncation and statement got terminated error:
    nResult = SQLExecDirect(handleStatement, L"INSERT INTO Wallet (WalletID, Name) VALUES (1, 'SomethingTooLong')", SQL_NTS);
    if (!SQL_SUCCEEDED(nResult))
        printErr(handleStatement, SQL_HANDLE_STMT);

    // and now run a query on the same statement and check in the db: Has been inserted just fine
    nResult = SQLExecDirect(handleStatement, L"INSERT INTO Wallet (WalletID, Name) VALUES (2, 'Fan')", SQL_NTS);
    if (!SQL_SUCCEEDED(nResult))
        printErr(handleStatement, SQL_HANDLE_STMT);
    // actually we should now free all handles properly...
    return 0;
}

这个程序的输出是:

ERROR; native: 8152; state: 22001; msg: [Microsoft][ODBC SQL Server Driver][SQL Server]String or binary data would be truncated. ERROR; native: 3621; state: 01000; msg: [Microsoft][ODBC SQL Server Driver][SQL Server]The statement has been terminated.

但是最后一个没有错误的插入查询,使用语句,已经成功执行:检查你的数据库并查看该行已经被插入(并且 SQLExecDirect 没有返回任何错误)。

SQL_INVALID_HANDLE 参见此处:https://msdn.microsoft.com/en-us/library/ms716219(v=vs.85).aspx

关于c++ - 我可以在出错后使用 ODBC 语句吗(是否有效)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41678381/

相关文章:

.net - 如何创建行特定的 sql 缓存依赖项?

sql - 在 SQL 查询中显示串联值

mysql - Microsoft OLE DB Provider for ODBC 驱动程序错误

Java MySQL ODBCPreparedStatement 切断查询

c# - Python或C#中的项目构想

c++ - 在 Linux 中使用 Makefiles for C/C++ 构建和链接

C++11:显式复制值以用作右值引用的最短方法

mysql - 在 Rails 中获取 mysql 结果,但格式类似于 MySql 客户端界面

c++ - 请求 ‘insert’中的成员 ‘x’,非类类型

Excel ODBC 和 64 位服务器