下面的例子定义了两个函数,F1
和 F2
。 F1
调用 F2
并使用其结果。我想通过在包规范中声明它来仅公开访问 F1
,并使 F2
对包私有(private)。
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 上下文,它只知道公共(public)包函数,而不是 PL/SQL 上下文,它知道私有(private)包内容。但是这个问题的提问者并没有提供示例代码,而且回答者似乎也收回了答案,所以我还是想提出这个问题。
有没有一种方法可以从其他函数调用包私有(private)函数而不需要在包的公共(public)规范中公开它们?
最佳答案
无法在 SQL 中使用私有(private) PL/SQL 函数。即使当 SQL 语句嵌入到与该私有(private)函数相同的包主体中的代码中时,情况仍然如此。在这种讨论中,“上下文切换”这个词被广泛使用(我自己过去也做过一些使用),但这是一种粗略的简化,更不用说扭曲了。但基本原则仍然如您所说:
[SQL] only knows about public package functions
所以问题变成了:您的(真实的)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;
/
显然这可能不是您正在寻找的解决方案,但这是我在不知道您的基本要求的情况下所能做的最好的解决方案。
关于oracle - 未在规范中声明就无法调用 Oracle 包函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58914253/