在Oracle数据库上使用return子句时,插入语句中函数的双重执行



我们在Oracle DB 21.3版本上发现了一个错误(19.3版本也测试了同样的错误(。如果在insert语句中使用函数,并使用return子句返回值,则结果是在insert statemet中调用的函数执行两次!!!

下面是一个使用为序列创建下一个值的函数的示例。我知道你可以用";。nextval";直接执行(如图所示工作正常(,但这只是演示函数双重执行的示例。我可以使用任何其他函数,并且会被执行两次(例如计算一些东西(。

您可以使用以下示例来测试它是如何工作的:

create sequence seq_1;
create sequence seq_2;
create table test1000 (id number, a varchar2(4004));
create table test1001 (id number, a varchar2(1001));
create or replace function testfun return number is
v_a number;
begin
select seq_1.nextval into v_a from dual;
dbms_output.put_line('FUNCTION RETURNS SEQ_1 VALUE: '||v_a);
return v_a;
end;
/

如果你执行这个,你可以测试它:

declare
v_a varchar2(100);
begin
insert into test1000(id, a) values (seq_2.nextval, 'SEQ_1:'||testfun) returning a into v_a;
dbms_output.put_line(v_a);
insert into test1001(id, a) values (seq_2.nextval, 'SEQ_1:'||testfun) returning a into v_a;
dbms_output.put_line(v_a);
end;
/

它将输出:

FUNCTION RETURNS SEQ_1 VALUE: 1
SEQ_1:1
FUNCTION RETURNS SEQ_1 VALUE: 2
FUNCTION RETURNS SEQ_1 VALUE: 3
SEQ_1:3

你可以在第二个插入中看到双重执行。表test1001中的数据具有值2,但变量v_a中返回的值不同(值3(。在第一个插入中没有发生双重执行,而是在第二个插入中。我相信这是因为第二个表具有字段"0";a";最大大小大于4000的varchar2,我相信这与oracle如何处理扩展的varchar2-类型有关(max_STRING_size在我们的DB中扩展(。

我向Oracle报告了此错误。当我收到他们的回复时,我会更新这个。。。

上层样本的解决方案很简单。只需使用";。nextval";直接地如果你有任何不同的函数,解决方案是在插入语句中使用它之前执行函数(并将结果保存在变量中(,如下所示:

declare
v_a varchar2(100);
v_seq_id number;
begin
v_seq_id := testfun;
insert into test1000(id, a) values (seq_2.nextval, 'SEQ_1:'||v_seq_id) returning a into v_a;
dbms_output.put_line(v_a);
v_seq_id := testfun;
insert into test1001(id, a) values (seq_2.nextval, 'SEQ_1:'||v_seq_id) returning a into v_a;
dbms_output.put_line(v_a);
end;
/

结果将是正确的:

FUNCTION RETURNS SEQ_1 VALUE: 1
SEQ_1:1
FUNCTION RETURNS SEQ_1 VALUE: 2
SEQ_1:2

Oracle打开了一个错误-错误33847911

最新更新