过程中出现奇怪的错误“Ora-01001 Invalid cursor”

Posted

技术标签:

【中文标题】过程中出现奇怪的错误“Ora-01001 Invalid cursor”【英文标题】:Strange error "Ora-01001 Invalid cursor" in procedure 【发布时间】:2012-07-05 09:08:44 【问题描述】:

昨天我在我们的生产过程中处理了一个奇怪的错误。 语句执行失败

if v_cursor%isopen then
  close v_cursor; -- here was an error 
end if;

经过一番深入研究,我发现问题出在打开此光标的子程序中。我通过在子程序中添加输出参数 sys_refcursor 来修复错误。为了澄清情况考虑以下测试代码:

procedure nested_test(test  number,
                        p_cur out sys_refcursor)
  is  
    procedure nested_procedure_fail is
    begin      
      open p_cur for
        select 1, 2, 3, 4
          from dual
         where 1 = 0;
    end;

    procedure nested_procedure_success(p_cur out sys_refcursor) is
    begin
      open p_cur for
        select 1, 2, 3, 4
          from dual
         where 1 = 0;
    end;

  begin
    if test = 1 then
      nested_procedure_fail;
    else
      if test = 2 then
        nested_procedure_success(p_cur => p_cur);
      else
        open p_cur for
          select 6, 7, 8, 9
            from dual
           where 1 = 1;
      end if;
    end if;
  end;

  procedure test_fail is
    v_cur sys_refcursor;
  begin
    nested_test(test => 1, p_cur => v_cur);
    if v_cur%isopen then
      close v_cur;
    end if;
  end;

  procedure test_success is
    v_cur sys_refcursor;
  begin
    nested_test(test => 2, p_cur => v_cur);
    if v_cur%isopen then
      close v_cur;
    end if;
  end;

如果我尝试运行 test_success 一切正常,但在 test_fail 上我会收到一条消息

ORA-01001: 无效光标

我找不到有关此的任何信息。谁能解释为什么这段代码会失败?

Oracle 版本:

Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
PL/SQL Release 11.2.0.3.0 - Production
CORE    11.2.0.3.0  Production
TNS for Solaris: Version 11.2.0.3.0 - Production
NLSRTL Version 11.2.0.3.0 - Production

【问题讨论】:

【参考方案1】:

这似乎是错误 7174888,或者至少与它密切相关。对此的描述是“当 sys_refcursor 传递给另一个过程时引发 ORA-6504”,但如果我更改 test_fail 以进行提取,我也可以做到这一点:

  procedure test_fail is
    v_cur sys_refcursor;
    a number;
    b number;
    c number;
    d number;
  begin
    nested_test(test => 1, p_cur => v_cur);
    if v_cur%isopen then
      fetch v_cur into a,b,c,d;
      close v_cur;
    end if;
  end;

我收到ORA-06504: PL/SQL: Return types of Result Set variables or query do not match

错误报告中的解决方法解决了获取和关闭问题。

将 ref 游标初始化为***别的非 NULL 值 它将被访问

  begin
    /* Dummy open to avoid bug 7174888 */
    open v_cur for 'select 1 from dual';
    nested_test(test => 1, p_cur => v_cur);
    if v_cur%isopen then
      fetch v_cur into a,b,c,d;
      close v_cur;
    end if;
  end;

【讨论】:

哇,谢谢!那解决了问题。有没有机会看到这个错误报告和描述? 遗憾的是,T&C 不允许我复制来自 Oracle 支持的信息。 (考虑一下,我可能什至不应该有解决方法的摘录)。如果您或您的 DBA 有权访问 Oracle 支持,那么您可以查找错误编号。 谢谢你,亚历克斯,我以为我快疯了!毕竟,oracle 只是一家价值数十亿美元的公司,因此希望他们的用户能够找到解决这些“小”错误的方法。【参考方案2】:

一个有趣的问题!只是想补充一些东西。

对我来说,真正的问题在于依赖 IS_OPEN 来确定游标是否有效。 Oracle 可能出于多种原因抛出 INVALID_CURSOR,并且可能有一个无效的“打开”游标。假设打开的游标必须有效似乎是合理的(因此我们可以从中获取或执行其他操作,例如简单的关闭),但情况不一定如此。

例如,您不能在远程过程调用(通过 dblinks)中使用游标变量。如果在 1 个数据库实例上调用 open 并在另一个实例上调用 fetch(如果在 db_A 上定义任何版本的nested_test,然后从 db_B 调用),同样的示例,即使使用 Alex 的解决方法,也会失败。然而,对 ISOPEN 的测试仍然会返回 TRUE,但是尝试使用游标(获取)会失败。

INVALID_CURSOR 可能因其他原因引发(例如超出最大打开游标,或者有时打开游标并等待一段时间再尝试使用它)。

话虽如此,据我所知没有“ISVALID”测试。 imo 最好的方法是在同一个程序或子程序中打开、获取和关闭游标。创建一个只负责打开一个游标的程序对我来说有点奇怪(但我确信这是有原因的),并且可能会导致难以解释的问题(比如这个)。如果您必须让另一个程序为您打开游标,那么您可能希望将获取并最终关闭游标的代码包含在匿名块中并捕获 INVALID_CURSOR 异常。

只是我的胡言乱语;-)

【讨论】:

以上是关于过程中出现奇怪的错误“Ora-01001 Invalid cursor”的主要内容,如果未能解决你的问题,请参考以下文章

Linux升级openssl时遇到的奇怪错误

Codeigniter 日志中出现奇怪的 404 错误

Emscripten 交叉编译的 CPython 中出现奇怪的导入错误

Haskell let-expression 中出现奇怪的类型错误——问题是啥?

无法使用 gcc 在 Linux 中编译任何 c++ 程序,出现一些奇怪的错误 [重复]

使用 Openlayers 的 WFS 请求中出现奇怪的错误