我们是否需要在每次调用 SQLExecdirect 之前调用 SQLAllocHandle 来分配一个 SQLHSTMT

Do we need to call SQLAllocHandle to allocate a SQLHSTMT before each call to SQLExecdirect

我需要执行一系列 T-sql 语句作为事务的一部分,在每次调用 SQLExecDirect 执行每个 t-[=19= 之前,我调用 SQLAllocHandle 分配 SQLHSTMT 类型的句柄] 陈述。如果我更改代码以在第一个 SQLExecDirect 之前对 SQLAllocHandle 进行一次调用,则对 SQLExecDirect 的后续调用将失败。

// This works
rc = SQLAllocHandle(SQL_HANDLE_STMT, *connection, &sqlStmtHandle);
rc = SQLExecDirect(sqlStmtHandle, (SQLCHAR *)statement1, SQL_NTS);
rc = SQLAllocHandle(SQL_HANDLE_STMT, *connection, &sqlStmtHandle);
rc = SQLExecDirect(sqlStmtHandle, (SQLCHAR *)statement2, SQL_NTS);


// This doesnt work. 
rc = SQLAllocHandle(SQL_HANDLE_STMT, *connection, &sqlStmtHandle);
rc = SQLExecDirect(sqlStmtHandle, (SQLCHAR *)statement1, SQL_NTS);
rc = SQLExecDirect(sqlStmtHandle, (SQLCHAR *)statement2, SQL_NTS);

这是预期的吗?如果是,为什么?是否有可以清楚解释语义的资源。在此处查看在线文档 https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlallochandle-function?view=sql-server-2017

"To request a statement handle, an application connects to a data source and then calls SQLAllocHandle before it submits SQL statements. "

这似乎表明我不应该重复调用 SQLAllocHandle,但我对此并不完全确定。

您不需要调用 SQLAllocHandle,但您确实需要通过调用 SQLFreeStmt 并将选项设置为 SQL_CLOSE 或调用 SQLCloseCursor 来重置现有句柄。

您可以查看语句句柄 (https://docs.microsoft.com/en-us/sql/odbc/reference/appendixes/statement-transitions?view=sql-server-2017) 的 ODBC 状态转换表,发现您不能直接从一个已执行的语句转到另一个执行。

仅在数据库初始化期间调用SQLAllocHandle(),否则可能会导致内存泄漏和性能问题。在 SQLExecDirect() 命令之后,查询结果存储在 hDatabaseStatement 中(根据结果的大小自动分配内存,所以不需要重复调​​用 SQLAllocHandle(SQL_HANDLE_STMT,...)),每次查询后都需要释放。

void InitializeDatabase() // call one time
{
        SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hDatabaseEnv);
        SQLAllocHandle(SQL_HANDLE_DBC, hDatabaseEnv, &hDatabase);
        SQLDriverConnect(/* */);
        SQLAllocHandle(SQL_HANDLE_STMT, hDatabase, &hDatabaseStatement);
}

void DestroyDatabase() // call one time
{
    SQLFreeStmt(hDatabaseStatement, SQL_CLOSE);
    SQLFreeHandle(SQL_HANDLE_STMT, hDatabaseStatement);
    SQLFreeHandle(SQL_HANDLE_DBC, hDatabase);
    SQLFreeHandle(SQL_HANDLE_ENV, hDatabaseEnv);        
}

void InsertItemDatabase(/**/)
{
    SQLExecDirect(hDatabaseStatement, wchar, SQL_NTS);
    SQLFreeStmt(hDatabaseStatement, SQL_CLOSE);
}