【问题标题】:Unable to call Oracle package function without declaring it in specification没有在规范中声明就无法调用 Oracle 包函数
【发布时间】:2019-11-18 20:49:20
【问题描述】:

以下示例定义了两个函数,F1F2F1 调用 F2 并使用其结果。我只想通过在包规范中声明 F1 来公开访问它,并将 F2 保留为包的私有。

CREATE OR REPLACE PACKAGE PBL1 AS     
  TYPE t_record IS RECORD(
         foo NUMBER
    );

    TYPE t_table IS TABLE OF t_record;

    FUNCTION F1 RETURN t_table PIPELINED;
END PBL1;

CREATE OR REPLACE PACKAGE BODY PBL1 AS
  FUNCTION F2 RETURN t_table PIPELINED AS
    r t_record;
  BEGIN
    r.foo := 17;
    PIPE ROW (r);
  END F2;

  FUNCTION F1 RETURN t_table PIPELINED AS
  BEGIN
    FOR x IN (SELECT * FROM F2())
    LOOP
        PIPE ROW (x);
    END LOOP;
  END F1;
END PBL1;

如果我尝试按原样编译包体,我会收到错误消息

PL/SQL: SQL Statement ignored
PL/SQL: ORA-00904: invalid ID
PL/SQL: PLS-000231: Function 'F2' may not be be used in SQL

如果我将F2 添加到包规范中,错误就会消失,我想避免这种情况。

我在answer to this question 中读到,这可能是由于上下文切换到了只知道公共包函数的 SQL 上下文,而不是知道私有包内容的 PL/SQL 上下文。但是,该问题的提问者没有提供示例代码,并且回答者似乎收回了他们的答案,所以我还是想提出这个问题。

有没有一种方法可以从其他函数调用包私有函数而无需在包的公共规范中公开它们?

【问题讨论】:

    标签: oracle plsql


    【解决方案1】:

    没有办法在 SQL 中使用私有 PL/SQL 函数。即使 SQL 语句嵌入到与该私有函数相同的包体中的代码中,这仍然是正确的。在这种讨论中,“上下文切换”这个词被广泛使用(我自己过去也做过一些讨论),但这是一种粗略的简化,更不用说扭曲了。但基本原则还是如你所说:

    [SQL] 只知道公共包函数

    所以问题就变成了:你的(真实的)F2() 函数必须流水线化吗?你不能只填充一个嵌套表吗?使用该实现F1() 可以调用F2() 然后遍历返回的表。像这样:

    CREATE OR REPLACE PACKAGE PBL1 AS     
      TYPE t_record IS RECORD(
             foo NUMBER);
    
        TYPE t_table IS TABLE OF t_record;
    
        FUNCTION F1 RETURN t_table PIPELINED;
    
    END PBL1;
    /
    CREATE OR REPLACE PACKAGE BODY PBL1 AS
    
      FUNCTION F2 RETURN t_table AS
        r t_record;
        t t_table := new t_table() ;
      BEGIN
        r.foo := 17;
        t.extend();
        t(1) := r;
    
        return t;    
      END F2;
    
      FUNCTION F1 RETURN t_table PIPELINED AS
        r t_record;    
        t t_table;
      BEGIN
        t := f2;
    
        FOR x IN 1 .. t.count()
        LOOP
            r := t(x);    
            PIPE ROW (r);
        END LOOP;
    
      END F1;
    END PBL1;
    /
    

    显然,这可能不是您正在寻找的解决方案,但这是在不了解您的基本要求的情况下我能做到的最好的解决方案。

    【讨论】:

    • 使用嵌套表的建议非常有用;它让我了解PL/SQL 中的收藏。
    【解决方案2】:

    不,没有。你在另一个问题中读到的答案一针见血。私有子程序只能被其他子程序和包的初始化部分引用。

    从 SQL 层,您调用的任何函数都必须是模式级函数(创建或替换函数)或在包规范中列出。

    【讨论】:

      猜你喜欢
      • 2014-04-03
      • 2013-01-21
      • 2020-07-15
      • 2020-05-15
      • 2018-07-11
      • 1970-01-01
      • 1970-01-01
      • 2012-01-21
      • 1970-01-01
      相关资源
      最近更新 更多