Oracle 12 在 SQL 中是否存在本地集合类型的问题?
Does Oracle 12 have problems with local collection types in SQL?
长话短说,我建议讨论您在下面看到的代码。
当运行时:
Oracle 11 编译器引发
"PLS-00306: wrong number or types of arguments tips in call to 'PIPE_TABLE'"
"PLS-00642: Local Collection Types Not Allowed in SQL Statement"
Oracle 12编译如下包没有这样的警告,但是运行时有惊喜
when executing the anonymous block as is - everything is fine
(we may pipe some rows in the pipe_table
function - it doesn't affect)
now let's uncomment the line with hello;
or put there a call to any procedure, and run the changed anonumous block again
we get "ORA-22163: left hand and right hand side collections are not of same type"
问题是:
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;
/
是的,在 Oracle 12c 中,您可以在 SQL 中使用本地集合类型。
文档 Database New Features Guide 说:
PL/SQL-Specific Data Types Allowed Across the PL/SQL-to-SQL Interface
The table operator can now be used in a PL/SQL program on a collection whose data type is declared in PL/SQL. This also allows the data type to be a PL/SQL associative array. (In prior releases, the collection's data type had to be declared at the schema level.)
但是,我不知道为什么你的代码不起作用,也许这个新功能仍然存在错误。
我摆弄了你的例子。 Oracle 12c 如何在 SQL 语句中使用 PL/SQL 集合的技巧是 Oracle 创建具有兼容 SQL 类型属性的代理模式对象类型,并在查询中使用这些代理类型。你的情况看起来像一个错误。我跟踪了执行过程,代理类型如果不存在则只创建一次。因此,在执行流水线函数期间,有效类型既不会更改也不会重新编译(不知道是否使用 ALTER 语句完成了隐式重新编译)。并且仅当您在 pipe_table
函数中使用 p
参数时才会出现此问题。如果您不调用 l_table := p;
,即使启用了方法调用,代码也会成功执行。
在进一步的实验中,我们发现问题比想象的还要严重。
例如,包中使用的不同元素 buggy_report
我们可以得到一个 ORA-03113: end-of-file on communication channel
当 运行 脚本(在问题中)。可以通过将 t_id_table
的类型更改为 VARRAY
或 TABLE .. INDEX BY ..
来完成。有很多方法和变体导致我们出现不同的异常,这与本文无关post。
更有趣的是 buggy_report
包规范的编译时间最多可能需要 25 秒,
通常情况下大约需要 0.05 秒。我可以肯定地说,这取决于 pipe_table
函数声明中是否存在 TYPE t_id_table
参数,并且 "long time compilation" 发生在 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;
/
长话短说,我建议讨论您在下面看到的代码。
当运行时:
Oracle 11 编译器引发
"PLS-00306: wrong number or types of arguments tips in call to 'PIPE_TABLE'"
"PLS-00642: Local Collection Types Not Allowed in SQL Statement"
Oracle 12编译如下包没有这样的警告,但是运行时有惊喜
when executing the anonymous block as is - everything is fine (we may pipe some rows in the
pipe_table
function - it doesn't affect)now let's uncomment the line with
hello;
or put there a call to any procedure, and run the changed anonumous block again we get "ORA-22163: left hand and right hand side collections are not of same type"
问题是:
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;
/
是的,在 Oracle 12c 中,您可以在 SQL 中使用本地集合类型。
文档 Database New Features Guide 说:
PL/SQL-Specific Data Types Allowed Across the PL/SQL-to-SQL Interface
The table operator can now be used in a PL/SQL program on a collection whose data type is declared in PL/SQL. This also allows the data type to be a PL/SQL associative array. (In prior releases, the collection's data type had to be declared at the schema level.)
但是,我不知道为什么你的代码不起作用,也许这个新功能仍然存在错误。
我摆弄了你的例子。 Oracle 12c 如何在 SQL 语句中使用 PL/SQL 集合的技巧是 Oracle 创建具有兼容 SQL 类型属性的代理模式对象类型,并在查询中使用这些代理类型。你的情况看起来像一个错误。我跟踪了执行过程,代理类型如果不存在则只创建一次。因此,在执行流水线函数期间,有效类型既不会更改也不会重新编译(不知道是否使用 ALTER 语句完成了隐式重新编译)。并且仅当您在 pipe_table
函数中使用 p
参数时才会出现此问题。如果您不调用 l_table := p;
,即使启用了方法调用,代码也会成功执行。
在进一步的实验中,我们发现问题比想象的还要严重。
例如,包中使用的不同元素 buggy_report
我们可以得到一个 ORA-03113: end-of-file on communication channel
当 运行 脚本(在问题中)。可以通过将 t_id_table
的类型更改为 VARRAY
或 TABLE .. INDEX BY ..
来完成。有很多方法和变体导致我们出现不同的异常,这与本文无关post。
更有趣的是 buggy_report
包规范的编译时间最多可能需要 25 秒,
通常情况下大约需要 0.05 秒。我可以肯定地说,这取决于 pipe_table
函数声明中是否存在 TYPE t_id_table
参数,并且 "long time compilation" 发生在 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;
/