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

时间:2015-10-16 05:14:25

标签: 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;
/

3 个答案:

答案 0 :(得分:1)

在进一步的实验中,我们发现问题甚至比假设的更深。

例如,在包buggy_report中使用的各种元素,我们可以获得ORA-03113: end-of-file on communication channel 在运行脚本时(在问题中)。可以将t_id_table的类型更改为VARRAYTABLE .. 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-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;
/

答案 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;,即使启用了方法调用,代码也会成功执行。