【问题标题】:Invalid cursor state when attempt to close尝试关闭时游标状态无效
【发布时间】:2009-07-18 18:09:39
【问题描述】:

我有大量的 INSERT 语句要运行。当我运行它们时,我可以理解地得到“超出最大打开游标”。

OK Oracle,所以我将在运行 INSERT 语句后立即关闭游标。

SQLCloseCursor(hStmt)

但是 Oracle 说这个“无效的游标状态”。

为什么 Oracle 对我关闭游标不满意?我通过 MySQL dsn 测试了相同类型的查询,MySQL 似乎没有抱怨在 INSERT 语句后立即关闭游标。

编辑 --

这是执行查询的代码

CHECK 是一个检查 SQLRESULT 并记录错误的函数,如果成功则返回 TRUE,如果失败则返回 FALSE。 "status()" 使用 SQLGetDiagRec() 记录其余的错误信息。

SQLINTEGER 非查询(字符 * 非查询) { SQLINTEGER rowsAffected = 0 ; SQLHANDLE hStmt ; CHECK( SQLAllocHandle( SQL_HANDLE_STMT, hConn, &hStmt ), "为语句分配句柄" ) ; if( !CHECK( SQLExecDirectA( hStmt, (SQLCHAR*)nonquery, SQL_NTS ), "执行查询" ) ) { 状态(SQL_HANDLE_STMT,hStmt,__LINE__); } // 获取受影响的行 if( !CHECK( SQLRowCount( hStmt, &rowsAffected ), "非查询后的行数" ) ) { 状态(SQL_HANDLE_STMT,hStmt,__LINE__); } if( ! CHECK( SQLFreeStmt( hStmt, SQL_CLOSE ), "Sql free stmt" ) ) { 状态(SQL_HANDLE_STMT,hStmt,__LINE__); } // 特写。 if( !CHECK( SQLCloseCursor( hStmt ), "关闭光标" ) ) { 状态(SQL_HANDLE_STMT,hStmt,__LINE__); } 返回行受影响; }

我这样称呼非查询

非查询(“sql语句”);

所以我得到:

[24000][0] [Oracle][ODBC]游标状态无效。

起初,(可能是因为 INSERT 语句没有游标?),后来,在多次插入之后(非查询只是简单地连续调用很多次),我得到了

ORA-01000: 超出最大打开游标

【问题讨论】:

    标签: c++ oracle odbc


    【解决方案1】:

    我认为你关闭了两次光标:

    SQLFreeStmt(SQL_ CLOSE) - 来自MSDN:“关闭与 StatementHandle 关联的游标(如果已定义)并丢弃所有待处理的结果

    因此,调用 SQLCloseCursor 将返回“无效游标状态”(请参阅​​ Note)。

    我认为你需要的是:

    SQLCloseCursor(hStmt);
    
    SQLFreeHandle(SQL_HANDLE_STMT,hStmt) // replace SQLFreeStmt with this
    

    【讨论】:

    • +1 是的——那肯定是个问题!不知道我是怎么错过的:-(
    • 您似乎很快就编辑了您的帖子,所以我看不到历史记录 - 一个糟糕的 SO 功能。一点不要让事情复杂化——一旦你调用 SQLFreeStmt,你就不能再使用语句句柄了,这似乎是提问者的问题,而不是光标的问题,我认为这是红鲱鱼。
    【解决方案2】:

    我有大量的 INSERT 要运行的语句。当我运行它们时,我 可以理解地获得“最大开放 超出光标”。

    实际上,这对我来说没有意义 - INSERT 语句不使用游标。你确定这是你得到的错误吗?这可以解释你得到的原因:

    SQLCloseCursor(hStmt)

    但甲骨文对此表示“无效 光标状态。”

    因为没有光标。

    MySQL 不抱怨的事实可能是由于驱动程序的差异。它们都是 ODBC 3.0 吗?

    编辑:查看您的代码后,我有两个问题。首先,我们能看到导致问题的 SQL 命令吗?其次,SQLRowCount 是一个有点可疑的函数——许多数据库对于某些查询类型不支持它,我可以看到它本身可能需要一个游标。您可以尝试使用不调用 SQLRowCount 的函数版本吗?

    Edit2:认为 Alan 已经发现了您的问题。您释放一条语句,然后在其上调用 close cursor - 这是 ODBC 未定义的。如果您确实认为需要关闭游标(我不需要),请在释放语句之前将其关闭。

    【讨论】:

    • dev.mysql.com/doc/refman/5.1/en/connector-odbc-versions.html 表示 MySQL 驱动程序是“1 级和 2 级”。我相信我的 oracle 驱动程序必须是 ODBC 2 oracle.com/technology/software/tech/windows/odbc/index.html 我认为插入语句不应该有游标是有道理的。但我怎么仍然得到“超出最大游标”?
    • MSDN 说“无效光标”仅由 3.0 驱动程序返回。我会忘记 MySQL 并专注于 Oracle - 你能发布一个说明问题的小例子吗?您可能还想在更面向 Oracle 的网站上发布问题,因为我觉得没有太多 SO 常客使用它 - 恐怕我自己没有。
    【解决方案3】:

    插入确实使用光标。如果您要进行大量插入,则应该重用光标。 模式应该是

    OPEN cursor
      start loop
         BIND variables
         EXECUTE CURSOR
      end loop
    CLOSE cursor
    

    在您的情况下,我没有看到显式打开的游标,所以我猜您正在依赖 c++ 来隐式管理它,而且它似乎做得不好。从代码here 来看,您需要将 SQLPrepare 放入逻辑中。

    【讨论】:

    • 你说“插入确实使用光标”——这有什么证据吗?根据 SQL 标准,它们当然不在 Sybase、SQLServer 或 MySQL 上,或者如果我没记错的话。
    • 这可能是一个术语。 download.oracle.com/docs/cd/B19306_01/appdev.102/b14354/… "Oracle 为所有数据定义和数据操作语句隐式声明了一个游标,包括只返回一行的 SELECT 语句(查询)"
    猜你喜欢
    • 1970-01-01
    • 2012-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多