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

Does Oracle 12 have problems with local collection types in SQL?

长话短说,我建议讨论您在下面看到的代码。

当运行时:

问题是: 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 的类型更改为 VARRAYTABLE .. 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-22163ORA-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;
/