当抛出 ORA 时,我遇到了包初始化状态的奇怪行为。这是我在 Oracle 12c 上运行的示例:
create or replace package pkg is
v_num number := pkg_two.getnum_two;
function getnum return number;
end;
create or replace package pkg_two is
v_num_two number := 1;
function getnum_two return number;
end;
create or replace package body pkg is
function getnum return number is
begin
return v_num;
end;
end;
create or replace package body pkg_two is
function getnum_two return number is
begin
return v_num_two;
end;
begin
dbms_lock.sleep(10);
end;
现在出现了奇怪的行为。我在 SQLPlus 中运行以下代码,并在 5 秒后中断它:
declare
v_number number;
begin
select pkg.getnum into v_number from dual;
dbms_output.put_line('output: ('||v_number||')');
end;
此中断抛出了 ORA-01013。然后我再次运行它,仅几毫秒后我就得到了:
output: ()
这很奇怪,因为在 12c 中,只有在初始化完成后才应将包设置为初始化,正如我在本文中发现的那样:https://rogertroller.com/2018/05/16/package-initialization-changes-between-oracle-11g-and-oracle-12c/
同样奇怪的是,如果我用“:=”替换“SELECT INTO”,则行为正如文章所述:
declare
v_number number;
begin
v_number := pkg.getnum;
dbms_output.put_line('output: ('||v_number||')');
end;
因此,在执行两次相同的运行程序后,我得到(第二次运行后 10 秒):
output: (1)
有人能解释一下这种行为是否是预期的吗?如果是,不使用“SELECT INTO”子句是否会发生这种情况?
我没有看到您在 19c 中描述的行为,因此自您引用的文章中的更改以来,它大概已经进行了进一步修改。目前尚不清楚这是在描述 12cR1 还是 12R2,因为它被标记为两者;但这篇类似的文章和Steven Feuerstein 的LiveSQL 演示指出它最初在 12cR1 中发生了变化。它可能在这两个版本之间、18c 或 19c 中或两者之间的某个补丁中发生了进一步变化。您还没有说您在哪个版本和补丁集上看到了行为上的差异。
无论如何...版本执行以下操作:
似乎表现得和你预期的一样,与文章所说的一致。该版本完全是 PL/SQL - 您正在调用包函数并将其返回值直接分配给 PL/SQL 变量,因此不涉及 SQL。
执行的版本:
表现不同(对您而言,但在 19c 中不是),但在 PL/SQL 和 SQL 之间有上下文切换。
select into...
本质上是退出 PL/SQL 来执行 SQL 语句,并将结果返回到 PL/SQL 变量中。(我想如果您直接select pkg.getnum from dual
在 SQL 中执行此操作,而不使用匿名块,您会看到同样的事情?)这表明对初始化行为的更改最初以不同的方式处理。无论使用何种机制来保持包未初始化(或未实例化),或者可能将其恢复到该状态,当会话中发生异常时,似乎只适用于在 PL/SQL 上下文中看到的情况。早期的迭代似乎忽略了 SQL 上下文中发生的相同事情。而一些后续补丁或版本对其进行了改进,使其在两种上下文中以相同的方式工作。(通常都是这样 - 错误 34969407 表明它可能仍然不完全一致。)知道它究竟是什么时候改变的会很有趣。
这必然是猜测,部分原因是我没有 12c DB 可以再次测试,也是因为我看不到关于为什么更改它或者它内部如何运作的任何细节 - 这不是我所期望的 - 或者该领域的任何文档更改。
由于在后续版本中已修复或至少改进了此问题,因此我不会说行为上的差异是“预期的”,因为它看起来不像是故意的。不过,根据您所看到的情况,我预计会在 12cR1 以及可能的一些后续版本/补丁集中看到此问题,但不会在较新的版本中看到。即使如此,也可能只有在涉及上下文切换时才会出现。