总而言之,我建议讨论下面你看到的代码。
运行时:
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;
/
答案 0 :(得分:1)
在进一步的实验中,我们发现问题甚至比假设的更深。
例如,在包buggy_report
中使用的各种元素,我们可以获得ORA-03113: end-of-file on communication channel
在运行脚本时(在问题中)。可以将t_id_table
的类型更改为VARRAY
或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中使用本地集合类型的实现中显然存在错误。
获取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;
/
答案 1 :(得分:0)
是的,在Oracle 12c中,您可以在SQL中使用本地集合类型。
文档Database New Features Guide说:
PL / SQL-to-SQL接口允许的PL / SQL特定数据类型
表运算符现在可以在PL / SQL程序中用于其数据类型在PL / SQL中声明的集合。这也允许数据类型是PL / SQL关联数组。 (在以前的版本中,必须在架构级别声明集合的数据类型。)
但是,我不知道为什么你的代码不起作用,也许这个新功能还有一个bug。
答案 2 :(得分:0)
我摆弄着你的榜样。 Oracle 12c如何在SQL语句中使用PL / SQL集合的技巧是Oracle创建具有兼容SQL类型属性的代理模式对象类型,并在查询中使用这些代理类型。你的案子看起来像个bug。我跟踪了执行,如果不存在,代理类型只创建一次。因此,在执行流水线函数期间,有效类型不会更改也不会重新编译(不知道是否使用ALTER语句进行了隐式重新编译)。如果您在p
函数中使用pipe_table
参数,则只会出现此问题。如果您没有调用l_table := p;
,即使启用了方法调用,代码也会成功执行。