Короче говоря, предлагаю обсудить код, который вы видите ниже.

При запуске:

  • Компилятор Oracle 11 поднимает

    «PLS-00306: неправильное количество или типы подсказок аргументов при вызове 'PIPE_TABLE'»

    «PLS-00642: типы локальных коллекций, недопустимые в операторе SQL»

  • Oracle 12 компилирует следующий пакет без таких предупреждений, но у нас есть сюрприз во время выполнения

    при выполнении анонимного блока как есть - все нормально (мы можем передать некоторые строки в функцию pipe_table - это не влияет)

    теперь раскомментируем строку с помощью hello; или поместим туда вызов любой процедуры и снова запустим измененный анонимный блок мы получаем «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;
/
12
diziaq 16 Окт 2015 в 08:14

3 ответа

Лучший ответ

В ходе дальнейших экспериментов мы обнаружили, что проблемы даже глубже, чем предполагалось.

Например, изменяя элементы, используемые в пакете 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
diziaq 6 Ноя 2015 в 07:40

Я повозился с твоим примером. Уловка, с помощью которой Oracle 12c может использовать коллекции PL / SQL в операторах SQL, заключается в том, что Oracle создает типы объектов суррогатной схемы с совместимыми атрибутами типов SQL и использует эти суррогатные типы в запросе. Ваш случай похож на ошибку. Я проследил выполнение, и суррогатные типы создаются только один раз, если не существуют. Таким образом, эффективный тип не изменяется и не перекомпилируется (не знаю, выполняется ли неявная перекомпиляция с помощью оператора ALTER) во время выполнения конвейерной функции. И проблема возникает, только если вы используете параметр p в функции pipe_table. Если вы не вызываете l_table := p;, код выполняется успешно даже при включенном вызове метода.

0
Husqvik 2 Ноя 2015 в 02:26

Да, в Oracle 12c вам разрешено использовать локальные типы коллекций в SQL.

В документации Руководство по новым функциям базы данных говорится:

Типы данных, специфичные для PL / SQL, разрешенные в интерфейсе PL / SQL-to-SQL

Оператор таблицы теперь можно использовать в программе PL / SQL для коллекции, тип данных которой объявлен в PL / SQL. Это также позволяет типу данных быть ассоциативным массивом PL / SQL. (В предыдущих выпусках тип данных коллекции нужно было объявлять на уровне схемы.)

Однако я не знаю, почему ваш код не работает, возможно, в этой новой функции все еще есть ошибка.

0
Community 20 Июн 2020 в 09:12