在把ORACLE的数据库从8i升级到9i及以上的时候,一般认为原有的PLSQL程序应该完全兼容,即运行过程和运行结果完全一致。遗憾的是,事实并非如此,由于ORACLE PLSQL引擎的升级,它对某些代码解释做了更改,导致某些代码会有不同的运行结果。各位在升级数据库时必须重视,否则将导致无法估量的损失和难以恢复的灾难。 1、PLSQL表作为参数传递 先看以下代码,在ORACLE 8i和9i中的运行结果。
declare
type test_rec is record
(
col_1 varchar2(100)
);
type test_tbl is table of test_rec index by binary_integer;
l_tbl test_tbl;
procedure change_value
is
begin
l_tbl(1).col_1 := 'I am changed!';
end;
procedure sub_test(pi_str in varchar2)
is
begin
dbms_output.put_line('before: '||pi_str);
change_value;
dbms_output.put_line('after : '||pi_str);
end;
begin
l_tbl(1).col_1 := 'I am ok!';
sub_test(l_tbl(1).col_1);
exception
when others then
dbms_output.put_line(sqlerrm);
end;
示例代码非常简单,即将PLSQL表的某个成员变量当作参数给另一过程,此过程改变了原PLSQL表的值,但未改变传入参数的值(当然不能改,表示为IN的参数的值是不能改的),观看改变前后,传入参数的值在Oracle 8i和9i的变化。 运行结果:
Oracle 8i Oracle 9i
before: I am ok! before: I am ok!
after : I am ok! after : I am changed!
显然运行结果不一样!在Oracle 8i中,传入参数的值在原PLSQL表的值改变前后未变化,而在Oracle 9i中,传入参数的值被改动了。
declare
type test_rec is record
(
col_1 varchar2(100)
);
type test_tbl is table of test_rec index by binary_integer;
l_tbl test_tbl;
procedure change_value
is
begin
l_tbl(1).col_1 := 'I am changed!';
end;
procedure sub_test(pi_str in varchar2)
is
begin
dbms_output.put_line('before: '||pi_str);
change_value;
dbms_output.put_line('after : '||pi_str);
end;
begin
l_tbl(1).col_1 := 'I am ok!';
sub_test(l_tbl(1).col_1);
exception
when others then
dbms_output.put_line(sqlerrm);
end;
示例代码非常简单,即将PLSQL表的某个成员变量当作参数给另一过程,此过程改变了原PLSQL表的值,但未改变传入参数的值(当然不能改,表示为IN的参数的值是不能改的),观看改变前后,传入参数的值在Oracle 8i和9i的变化。 运行结果:
Oracle 8i Oracle 9i
before: I am ok! before: I am ok!
after : I am ok! after : I am changed!
显然运行结果不一样!在Oracle 8i中,传入参数的值在原PLSQL表的值改变前后未变化,而在Oracle 9i中,传入参数的值被改动了。
解决方案 »
- ORA-09925: Unable to create audit trail file
- SQL语句写入存贮过程,缺插入不了数据,帮忙看看什么原因?
- oracel的安装问题
- 求oracle数据库全备份+日志备份方案 谢谢
- ORACLE开始就让我们郁闷。。。
- 关于sql_trace参数值的问题
- 给了年月和第几周 如'2006073',如何得到本周是从哪天开始到哪天结束的呀!!
- 在存储过程中能否用游标来返回其他用户的数据集?我建同义词提示无此表!
- 如何用SELECT 计算出上周的开始和结束时间?
- oracle 游标 循环
- Oracle奇怪问题:Sql语句在客户端通过Plsql执行没有反映,但在服务器上却可以执行.
- 自增长列
DECLARE
l_test VARCHAR2(10);
type test_rec is record (col_a varchar2(100));
TYPE test_tab IS TABLE OF test_rec INDEX BY BINARY_INTEGER;
l_test_tab test_tab;
FUNCTION return_tbl ( pi_dummy IN VARCHAR2 )
RETURN test_tab
IS
l_tbl test_tab;
BEGIN
l_tbl.DELETE;
l_tbl(1).col_a := 'I am ok!';
RETURN l_tbl;
EXCEPTION
WHEN OTHERS THEN
l_tbl.DELETE;
RETURN l_tbl;
END;
BEGIN
l_test_tab := return_tbl('');
l_test := l_test_tab(1).col_a;
DBMS_OUTPUT.PUT_LINE ( 'before: ' || l_pol_num );
l_test := return_tbl('')(1).col_a;
DBMS_OUTPUT.PUT_LINE ( 'after : ' || l_test );
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE ( 'NO_DATA_FOUND exception!' );
END;
这段代码意味某函数返回一个PLSQL表类型的值,然后不同的引用方式,在屏幕上显示。 运行结果:
Oracle 8i Oracle 9i
before: I am ok! before: I am ok!
after : I am ok! NO_DATA_FOUND exception!
在Oracle 8i中,直接用函数名和下标访问PLSQL表的成员变量是合法的,但到了Oracle 9i,这种方式会导致一个运行期NO_DATA_FOUND意外,而产生不同的运行结果。 这个问题Oracle没有给出严格解释,只是指出这样的方式不再合法而已。大家同样需要重视这个问题,以免掉入这个陷阱。 数据库的升级导致PLSQL程序有不同的运行结果,这样的问题让人担忧,ORACLE的行事方式让人头疼。若有很多的FORM、REPORT和PLSQL存储过程,这个问题导致的代码检查修改和产生的工作量是非常巨大的,而且后期测试也需要消耗大量的资源。希望ORACLE以后不要再发生这样的事情,那真会伤了一直很信任你的粉丝们的心。 http://database.ccidnet.com/art/1107/20061220/982025_1.html
set serveroutput on size 1000000
declare
a number:=1;
b number:=11;
procedure change_value1
is
begin
a := 2;
b := 22;
end;procedure sub_test1(p1 in number,p2 in varchar2)
is
begin
dbms_output.put_line('before: '||p1||','||p2);
change_value1;
dbms_output.put_line('after : '||p1||','||p2);
end;begin
sub_test1(a,b);
exception
when others then
dbms_output.put_line(sqlerrm);
end;
/before: 1,11
after : 2,11