【问题标题】:SQLFetch() fails with the SQLState 24000 (Invalid Cursor)SQLFetch() 失败并返回 SQLState 24000(无效光标)
【发布时间】:2015-06-24 12:47:40
【问题描述】:

首先这个问题不是重复的:

因为它发生在一个干净的单一 SQL 环境中,之前没有执行任何操作!

我正在尝试使用带有以下 C++ ODBC 代码的准备好的 SQL 语句执行存储过程:

void ItemDBManager::UpgradeItem(SQLHSTMT hstmt, QUERY_UPGRADE_ITEM_PARAMS* upgradeItemParams)
{

// Preparing of the Query
RETCODE ret = SQLPrepare(hstmt, (UCHAR*)"{call dbo.upgrade_Item(?,?)}", SQL_NTS);
if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO)
{
   // Get diagnostics for the error and log it to a file
   ProcessSQLError(SQL_HANDLE_STMT, hstmt, "dbo.upgrade_Item failed!");
   SQLFreeStmt(hstmt, SQL_CLOSE);
   return;
}

// Binding of Parameters
SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_SBIGINT, SQL_BIGINT, 0, 0, &upgradeItemParams->OldItemUniqueNumber, 0, NULL);
SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 0, 0, &upgradeItemParams->UpgradedItemUID, 0, NULL);

// Binding of the Result
SQLINTEGER cb[44];
fill_n(cb, 44, SQL_NTS);
ITEM newItem; // My struct to hold the data returned by the Stored Procedure

// Binding of result Columns
int coldIdx = 0;

SQLBindCol(hstmt, ++colIdx, SQL_C_SBIGINT, &storeItem.UniqueNumber, 0, &cb[colIdx]);
SQLBindCol(hstmt, ++colIdx, SQL_C_ULONG, &storeItem.AccountUniqueNumber, 0, &cb[colIdx]);
[...]

// Zeroing the resulting struct
memset(&newItem, 0x00, sizeof(ITEM));

// Execution of the Statement
ret = SQLExecute(hstmt);
if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO)
{
   // Get diagnostics for the error and log it to a file
   ProcessSQLError(SQL_HANDLE_STMT, hstmt, "dbo.upgrade_Item failed!");
   SQLFreeStmt(hstmt, SQL_CLOSE);
   return;
}

// Fetching of a single result row
ret = SQLFetch(hstmt);
if (ret == SQL_NO_DATA || (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO))
{
   // <-- The Debugger enters here with the return code of -1 !!!!

   // Get diagnostics for the error and log it to a file
   ProcessSQLError(SQL_HANDLE_STMT, hstmt, "dbo.upgrade_Item failed!");
   SQLFreeStmt(hstmt, SQL_CLOSE);
   return;
}

[...] // Further Handling of the resulted ITEM Struct and freeing of the SQL Statement

}

调试器进入最后一个 IF 语句,返回码为-1,这是一个一般的 SQL_ERROR。

通过获取错误的诊断 Rect,我得到以下输出:

06-24 14:05:19| szSqlState    = 24000
06-24 14:05:19| pfNativeError = 0
06-24 14:05:19| szErrorMsg    = [Microsoft][ODBC SQL Server Driver]Invalid Cursorstatus 
06-24 14:05:19| pcbErrorMsg   = 58

06-24 14:05:19| ODBCRowNumber = -1 
06-24 14:05:19| SSrvrLine     = -1 
06-24 14:05:19| SSrvrMsgState = 0 
06-24 14:05:19| SSrvrSeverity = 0 
06-24 14:05:19| SSrvrProcname =  
06-24 14:05:19| SSrvrSrvname  =

直接在 Microsoft 的 SQL Management Studio 中执行查询给了我一个完美的结果,没有任何错误。

这个错误的原因是什么?如何进一步调试?

另外还有存储过程dbo.upgrade_Item的内容:

-- Stored Procedure dbo.upgrade_Item
@i_OldStoreUID BIGINT,
@i_NewItemNum  INT

AS

DECLARE @insertedIDs TABLE(Id BIGINT)

-- Updating of the ItemStore Table
INSERT INTO td_ItemStore (*my columns*)
OUTPUT INSERTED.UniqueNumber INTO @insertedIDs 
SELECT *my columns*, @i_NewItemNum
FROM td_ItemStore
WHERE UniqueNumber = @i_OldStoreUID

-- Returning the new inserted Item
SELECT * FROM td_ItemStore WHERE UniqueNumber = (SELECT TOP 1 Id FROM @insertedStoreUIDs)

非常感谢任何帮助!

【问题讨论】:

  • Invalid Cursorstatus 主要发生在查询结果错误的情况下。尝试将您的存储过程分成 2 个(插入其中一个并在另一个中返回结果)并检查。
  • @DumbCoder 好的,谢谢,这对我来说有点糟糕,因为我需要新创建的身份才能再次找到这个新插入的项目。有没有其他办法解决这个问题?
  • 不打扰只是为了确认两个步骤是否正常工作。然后修复一个不起作用并使用组合的一个。你需要首先弄清楚存储过程的哪一部分被破坏了。

标签: c++ sql stored-procedures odbc prepared-statement


【解决方案1】:

显然我遇到了与这个问题相同的问题:PDO with MSSQL returns Invalid Cursor

问题出在我的存储过程中。为了获得正确的光标,我必须通过设置 NOCOUNT ON 来禁用受影响行的输出

固定程序:

-- Stored Procedure dbo.upgrade_Item
@i_OldStoreUID BIGINT,
@i_NewItemNum  INT

AS

BEGIN
   SET NOCOUNT ON;

   DECLARE @insertedIDs TABLE(Id BIGINT)

   -- Updating of the ItemStore Table
   INSERT INTO td_ItemStore (*my columns*)
   OUTPUT INSERTED.UniqueNumber INTO @insertedIDs 
   SELECT *my columns*, @i_NewItemNum
   FROM td_ItemStore
   WHERE UniqueNumber = @i_OldStoreUID

   -- Returning the new inserted Item
   SELECT * FROM td_ItemStore WHERE UniqueNumber = (SELECT TOP 1 Id FROM @insertedStoreUIDs)
END

【讨论】:

  • 启用 nocount 的另一种方法是阅读有关 SQLMoreResults 的信息,因为您需要调用它来逐步检查过程可能生成的多个结果。
猜你喜欢
  • 2011-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-19
相关资源
最近更新 更多