Oracle 12在SQL中是否存在本地集合类型的问题?

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)

diz*_*iaq 2

在进一步的实验中,我们发现问题比想象的还要深刻。

例如, 运行脚本(在问题中)时buggy_report我们可以得到包中使用的不同元素。ORA-03113: end-of-file on communication channel可以通过更改t_id_tabletoVARRAY或 的类型来完成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)