存储过程与匿名块 - 相同的数据,不同的结果

Posted

技术标签:

【中文标题】存储过程与匿名块 - 相同的数据,不同的结果【英文标题】:stored procedure vs anonymous block - same data, different results 【发布时间】:2016-12-05 12:22:49 【问题描述】:

当我使用匿名块和存储过程运行相同的代码时,我无法理解我得到的不同结果。他们都从数据字典中获取了一些细节,但看起来存储过程无法提取完整数据:

CREATE OR REPLACE PROCEDURE testing IS
    lv_schema VARCHAR2(10) := 'some_schema';
    total NUMBER;
    CURSOR tab_cur IS 
      SELECT    table_name
              , column_name
      FROM    all_tab_columns 
      WHERE   OWNER = lv_schema;
    in_record tab_cur%ROWTYPE;
  BEGIN
    total := 0;
    OPEN tab_cur;
    LOOP
      FETCH tab_cur INTO in_record;
      EXIT WHEN tab_cur%NOTFOUND;
      total := total + 1;
    END LOOP;
    CLOSE tab_cur;
    dbms_output.put_line(total);
  END testing;

对于我自己的架构,它给了我正确的结果(小架构,找到 13 个结果)。对于我们的一个较小的应用程序,它给出了不完整的结果(50,而不是预期的 83),而对于另一个(大)它列出了 0,而不是 5181)。

我已经驳回了这是因为特权的想法(当我直接使用 SELECT 查询数据字典时,我可以正确查看所有结果),并认为它可能与大小有关(当结果太多时光标失败,不知道),但是当我在匿名块中运行相同的代码时,我得到了所有正确的结果:

DECLARE
  lv_schema VARCHAR2(10) := 'some_schema';
  total NUMBER;
  CURSOR tab_cur IS 
    SELECT    table_name
            , column_name
    FROM    all_tab_columns 
    WHERE   OWNER = lv_schema;
  in_record tab_cur%ROWTYPE;
BEGIN
  total := 0;
  OPEN tab_cur;
  LOOP
    FETCH tab_cur INTO in_record;
    EXIT WHEN tab_cur%NOTFOUND;
    total := total + 1;
  END LOOP;
  CLOSE tab_cur;
  dbms_output.put_line(total);
END;

这里唯一的变化是“DECLARE”而不是“CREATE OR REPLACE FUNCTION testing IS”以及从 END 行中删除函数名称...任何人都可以指出我的一些解释吗?

谢谢!

【问题讨论】:

光标失败?如何?你有错误吗? 不,不,没有错误,很抱歉造成误解。这两段代码执行时都没有任何明显的错误,它们只是给出不同的结果。游标无法检索大量数据(我错误地描述为“失败”)的想法正在抓住稻草,我知道...... all_tab_columns 显示的列表取决于授予用户的权限。检查一下,如果它不起作用,请告诉我。 角色将在匿名块中处于活动状态,但在定义者权限过程中不处于活动状态,因此all_* 视图中的差异是可以预料的。 绅士们,我认为威廉·罗伯逊有一点 - 我读了一点(docs.oracle.com/cd/E25054_01/network.1111/e16543/…;搜索“角色如何在 PL/SQL 块中工作”)我尝试使用 DBA_TAB_COLUMNS,asn A Techtown 建议,但是对这两个数据字典表的访问权是从角色授予的,所以即使我似乎对这一切发生的原因有了答案,我仍在寻找一些补救策略。感谢所有参与者! 【参考方案1】:

William Robinson's comment 指出了一个解决方案。

这是来自 Oracle 文档中 Configuring Privilege and Role Authorization 的相关引用:

在具有定义者权限的命名块中使用的角色

在任何命名的 PL/SQL 块(存储过程、 以定义者的权限执行的函数或触发器。

我对使用的数据字典表 (all_tab_columns) 的访问权限是通过角色授予的。这就是为什么当我在存储过程中运行查询时没有考虑到它。这里的解决方案是创建一个过程,并在创建过程时使用AUTHID CURRENT_USER 子句强制它使用调用者权限而不是定义者权限(这是默认设置)。

【讨论】:

更多的是您对表本身的访问,而不是对 all_tab_columns 视图的访问。假设 HR 将 EMPLOYEES 的选择权限授予角色 HR_READONLY,SCOTT 拥有该权限。 all_ 视图将角色考虑在内,因此 SCOTT 在命令行或匿名块中查询时将看到 EMPLOYEES 列在 all_tables 等中,但不是从定义者权限过程内部,其中仅直接授予权限数。【参考方案2】:

您是否尝试过使用 DBA_TAB_COLUMNS。我认为它与权限有关。

下面是 ALL_TAB_COLUMNS 中的附加子句,DBA_TAB_COLUMNS 中没有。

and (o.owner# = userenv('SCHEMAID')
    or
    o.obj# in ( select obj#
                from sys.objauth$
                where grantee# in ( select kzsrorol
                                     from x$kzsro
                                   )
              )
    or /* user has system privileges */
      exists (select null from v$enabledprivs
              where priv_number in (-45 /* LOCK ANY TABLE */,
                                    -47 /* SELECT ANY TABLE */,
                                    -397/* READ ANY TABLE */,
                                    -48 /* INSERT ANY TABLE */,
                                    -49 /* UPDATE ANY TABLE */,
                                    -50 /* DELETE ANY TABLE */)
              )
   )**

【讨论】:

以上是关于存储过程与匿名块 - 相同的数据,不同的结果的主要内容,如果未能解决你的问题,请参考以下文章

存储过程中的 MySQL select 语句返回的结果与 proc 外部不同

oracle存储过程

怎么用ORACLE PLSQL匿名块调用存储过程

oracle中的创建过程,函数,包

Oracle创建存储过程

oracle存储过程连续执行结果不同