PL/SQL:对函数调用堆栈帧中的类型强制感到困惑

问题描述

考虑以下示例:

create or replace function f(n integer) return integer as
begin
  return n;
end;
/

begin
  dbms_output.put_line(f(3.8));
end;
/

3.8


PL/sql procedure successfully completed.

这对我来说毫无意义。显然,PL/sql 在进入函数退出函数时都忽略了 integer 规范。这只是一个错误吗?是语言开发者故意做出的设计选择吗?

这就是我觉得这令人困惑的原因。与以下示例进行比较:

declare
  x integer;
begin
  x := 3.8;
  dbms_output.put_line(x);
end;
/

4


PL/sql procedure successfully completed.

在本例中,符合数据类型规范。 PL/sql 不会抛出错误,但至少它会执行隐式强制转换,并且不会违反为 x 声明的数据类型 - 变量存储值 4,一个整数,而不是 3.8。

那么,PL/sql 是如何做第一个例子中的函数调用的呢?据我了解(从未接受过正式的计算培训),每当编译器或解释器找到一个函数调用时,它都会创建一个堆栈帧,其中包含传递给函数的参数和从函数返回的返回值的变量.当创建堆栈帧时,这些变量不是应该与函数声明中指定的相同的数据类型吗?如果堆栈帧的参数 3.8 有一个 integer 数据类型的字段,那么在它被存储到相应的变量中之前,它为什么不被强制为 4?返回值也是一样:如果函数返回 3.8 但调用者期望一个整数(因此堆栈帧中的相应变量应该是 integer),它如何能够接受返回值 3.8?

而且,最令人不安的是 - 为什么这种行为与涉及显式声明的变量时的行为不同(如我的第二个示例)?

感谢您分享您的想法!

解决方法

答案可以在 Oracle 数据库的文档中找到(您的问题与该文档完全没有任何关系)。

首先,上述数据库中的INTEGER是一个synonym for NUMBER(38)。在分配给 NUMBER(38) 变量 x 时,如在您的第二个示例中,根据分配规则,NUMBER(具有任意精度)文字 3.8 被四舍五入。

在您的第一个示例中,虽然没有发生赋值,因为 IN PL/SQL 子程序 are passed by reference 的参数和相同的引用(对 NUMBER 值 3.8)被返回。