Oracle 如何在dbms_sql.open_游标上解决ORA-29471?

Oracle 如何在dbms_sql.open_游标上解决ORA-29471?,oracle,plsql,dynamic-sql,Oracle,Plsql,Dynamic Sql,我正在使用Oracle 11.2.0.1.0,并试图让dbms_sql包正常工作。 但是,我不断得到ORA-29471错误,如下所示: DECLARE c INTEGER; BEGIN c := dbms_sql.open_cursor(); END; ORA-29471: DBMS_SQL access denied ORA-06512: at "SYS.DBMS_SQL", line 1017 ORA-06512: at line 4 甲骨文对此有如下说法: 绑定和执行时进行检查

我正在使用Oracle 11.2.0.1.0,并试图让dbms_sql包正常工作。 但是,我不断得到ORA-29471错误,如下所示:

DECLARE
  c INTEGER;
BEGIN
  c := dbms_sql.open_cursor();
END;

ORA-29471: DBMS_SQL access denied
ORA-06512: at "SYS.DBMS_SQL", line 1017
ORA-06512: at line 4
甲骨文对此有如下说法:

绑定和执行时进行检查。可选地,可以使用支票 为每个DBMS_SQL子程序调用执行。支票是:

  • 当前_用户在调用子程序时与调用最近的解析时相同
  • 调用子程序时启用的角色必须是调用最新解析时启用的角色的超集
与定义者权限子程序的使用一致,角色不 申请。如果任一检查失败,则会引发ORA-29470错误

据我所知,这两个条件都不适用于我的代码,因为代码不跨模式

Oracle(需要登录)网站建议我将security_level参数显式添加到dbms_sql.open_游标中。添加任何值(0/1/2)都不能解决问题

令我困惑的是,我在
dbms\u sql.open\u cursor
处得到了错误,这是安全级别的第一个定义

支持网站还提出了一个解决方案,包括设置:

alter system set "_dbms_sql_security_level" = 384 scope=spfile;
我还没试过。我更愿意将其视为最后手段,因为它涉及到禁用安全层,并且是不受支持的oracle功能。这几乎不是生产使用的理想环境。而且,它根本没有真正解决问题,只是隐藏了它

如何解决此错误?

您的代码引发
ORA-29471
的唯一原因(此时无法看到另一个原因)是您已通过提供无效的游标ID使
dbms\u sql
在会话中不可操作:

/* dbsm_sql detects invalid cursor ID in this session  */ 
SQL> declare
  2    c_1 number := 5;  -- invalid cursor ID. There is no cursor 
  3    l_res boolean;    -- opened with ID = 5     
  4  begin
  5    l_res := dbms_sql.is_open(c_1);
  6  end;
  7  /
declare
*
ERROR at line 1:
ORA-29471: DBMS_SQL access denied 
ORA-06512: at "SYS.DBMS_SQL", line 1104 
ORA-06512: at line 5 


/* An attempt to execute this simple anonymous PL/SQL block after 
   an invalid cursor ID has already been detected by the dbms_sql 
   in the current session will lead to ORA-29471 error  
*/

SQL> declare
  2    c_2 number;
  3  begin
  4    c_2 := dbms_sql.open_cursor();
  5  end;
  6  /
declare
*
ERROR at line 1:
ORA-29471: DBMS_SQL access denied 
ORA-06512: at "SYS.DBMS_SQL", line 1084 
ORA-06512: at line 4 

尝试在新建立的会话中执行该代码

解决方案可以是查看
v$session
视图

如果光标存在于列表中,则表示您仍可以使用它。然后从它的
sql\u id
中识别它,您可以进行检查。您可以在此处生成列表:

  select  sql_id, sql_text, count(*) as "OPEN CURSORS", user_name 
   from v$open_cursor
  where user_name <>'SYS' 
group by sql_text, user_name 
order by count(*) desc;
选择sql\u id、sql\u文本、计数(*)作为“打开的游标”、用户名
从v$open\u游标
其中用户名为“SYS”
按sql\u文本、用户名分组
按计数排序(*)说明;

更多。

该死的。我正要说同样的话,但你抢先说了+1我刚刚以与您相同的方式重新编写了错误,正要将SQL*Plus输出粘贴到我的答案中,这时我看到了您的答案。如果我对此感到如此不安,我就不会高估你的职位你说得对。建立新的会议解决了这个问题。我真不敢相信我花了一个多小时才发现这一点。谢谢@Nicholas Krasnov我们如何确定DBMS_SQL的特定会话无效?@NickKrasnov哇,我不敢相信重新打开一个新会话就能解决这个问题。多亏了你的回答,我才节省了几个小时。我可以请你强调一下建立新连接的部分吗?一些非鹰眼用户可能没有意识到这一点。谢谢:)一个解决方案可能是查看v$Session视图。更多。