diz*_*iaq 12 sql oracle collections cursor oracle12c
总而言之,我建议讨论下面你看到的代码.
运行时:
Oracle 11编译器引发了兴趣
"PLS-00306:调用'PIPE_TABLE'时错误的参数数量或类型提示"
"PLS-00642:SQL语句中不允许本地集合类型"
Oracle 12编译了以下软件包而没有这样的警告,但我们在运行时有一个惊喜
当按原样执行匿名块时 - 一切都很好(我们可能在
pipe_table
函数中管道一些行- 它不会影响)现在让我们取消注释
hello;
或者调用任何程序,并再次运行更改的anonumous块我们得到"ORA-22163:左手和右手边的集合不是同一类型"
问题是:Oracle 12是否允许SQL中的本地集合类型?如果是,那么代码有PACKAGE buggy_report
什么问题?
CREATE OR REPLACE PACKAGE buggy_report IS
SUBTYPE t_id IS NUMBER(10);
TYPE t_id_table IS TABLE OF t_id;
TYPE t_info_rec IS RECORD ( first NUMBER );
TYPE t_info_table IS TABLE OF t_info_rec;
TYPE t_info_cur IS REF CURSOR RETURN t_info_rec;
FUNCTION pipe_table(p t_id_table) RETURN t_info_table PIPELINED;
FUNCTION get_cursor RETURN t_info_cur;
END buggy_report;
/
CREATE OR REPLACE PACKAGE BODY buggy_report IS
FUNCTION pipe_table(p t_id_table) RETURN t_info_table PIPELINED IS
l_table t_id_table;
BEGIN
l_table := p;
END;
FUNCTION get_cursor RETURN t_info_cur IS
l_table t_id_table;
l_result t_info_cur;
BEGIN
OPEN l_result FOR SELECT * FROM TABLE (buggy_report.pipe_table(l_table));
RETURN l_result;
END;
END;
/
DECLARE
l_cur buggy_report.t_info_cur;
l_rec l_cur%ROWTYPE;
PROCEDURE hello IS BEGIN NULL; END;
BEGIN
l_cur := buggy_report.get_cursor();
-- hello;
LOOP
FETCH l_cur INTO l_rec;
EXIT WHEN l_cur%NOTFOUND;
END LOOP;
CLOSE l_cur;
dbms_output.put_line('success');
END;
/
Run Code Online (Sandbox Code Playgroud)
在进一步的实验中,我们发现问题比想象的还要深刻。
例如,
运行脚本(在问题中)时buggy_report
我们可以得到包中使用的不同元素。ORA-03113: end-of-file on communication channel
可以通过更改t_id_table
toVARRAY
或 的类型来完成TABLE .. INDEX BY ..
。有很多方法和变体会导致我们出现不同的异常,这不是本文的主题。
更有趣的一件事是,buggy_report
包规范的编译时间可能长达 25 秒,而通常需要大约 0.05 秒。我可以肯定地说,这取决于函数声明TYPE t_id_table
中是否存在参数pipe_table
,并且“长时间编译”发生在 40% 的安装情况中。所以看来这个问题是local collection types in SQL
在编译过程中潜在出现的。
所以我们看到Oracle 12.1.0.2在SQL中使用本地集合类型的实现上显然存在一个bug。
ORA-22163
获取的最小示例ORA-03113
如下。buggy_report
我们假设与问题中的包相同。
-- produces 'ORA-03113: end-of-file on communication channel'
DECLARE
l_cur buggy_report.t_info_cur;
FUNCTION get_it RETURN buggy_report.t_info_cur IS BEGIN RETURN buggy_report.get_cursor(); END;
BEGIN
l_cur := get_it();
dbms_output.put_line('');
END;
/
-- produces 'ORA-22163: left hand and right hand side collections are not of same type'
DECLARE
l_cur buggy_report.t_info_cur;
PROCEDURE hello IS BEGIN NULL; END;
BEGIN
l_cur := buggy_report.get_cursor;
-- comment `hello` and exception disappears
hello;
CLOSE l_cur;
END;
/
Run Code Online (Sandbox Code Playgroud)