Oracle: обнаружение исключения в типе construtor во время массового сбора - PullRequest
0 голосов
/ 03 октября 2018

Среда: Oracle 11g У меня есть тип ty1 с некоторыми аргументами, такими как s1, s2.

Если я использую его так:

SELECT ty1(s1,s2) BULK COLLECT INTO l_collection_of_ty1 FROM ...

Я получаю коллекцию ty1.

Теперь, если в одном из вызовов конструктора ty1 возникает исключение, соответствующему элементу моей коллекции присваивается значение NULL, но общий SELECT работает (без исключения, коллекция возвращена).

Мой вопрос, могу ли я обнаружить это сразу после SELECT без необходимости перебирать коллекцию?Может быть, есть даже способ получить доступ к исходному сообщению об ошибке аналогично тому, как SQL%BULK_EXCEPTION делает для DML?

Один из обходных путей, о котором я подумал, - это не использовать конструктор во время BULK COLLECT, а прочитать коллекции s1и s2, затем создайте TYPE в моем собственном цикле, где я могу обработать исключение, но это гораздо больше кода, и я бы предпочел, чтобы в Oracle была какая-то сборка.

Ответы [ 3 ]

0 голосов
/ 03 октября 2018

Я вижу только два варианта.

  1. Исключение потребляется внутри конструктора.
  2. Используется другой конструктор.

Пример:

create or replace type ty1 as object (p1 number
, constructor function  ty1 (p1 varchar2) 
    return self as result);

create or replace type body ty1 
is 
  constructor function ty1 (p1 varchar2) 
    return self as result is
    x number;
  begin
   raise_application_error(-20000,'Always Exception');
   return;
  end;
end;

Тест 1 без исключения:

declare
 type l_collection_of_ty1 is table of ty1;
 a varchar2(4000);
 x   l_collection_of_ty1;
begin 

--test1   select ty1(level) bulk collect into x from dual connect by level < 10;
     -- no exceptions 
 --test2  select ty1(level||1) bulk collect into x from dual connect by level < 10; 
       -- exceptions

  --test3 select ty1(null) bulk collect into x from dual connect by level < 10; 
       -- exceptions
end; 

В Test1 дБиспользует конструктор Attribute-Value.Он генерируется по умолчанию.
В Test2 db использует пользовательский конструктор.
В Test3 db не может определить, какой конструктор следует использовать. ()

0 голосов
/ 06 октября 2018

здесь тестовый пример, который демонстрирует, что все исключения выбрасываются через массовое выделение, но NO_DATA_FOUND отбрасывается.

-- remember to retreive dbms_output
SET SERVEROUTPUT ON

CREATE OR REPLACE FUNCTION p1 (v1 PLS_INTEGER)
   RETURN NUMBER
AS
BEGIN
   CASE v1
      WHEN 1
      THEN
         RAISE ACCESS_INTO_NULL;
      WHEN 2
      THEN
         RAISE CASE_NOT_FOUND;
      WHEN 3
      THEN
         RAISE COLLECTION_IS_NULL;
      WHEN 4
      THEN
         RAISE CURSOR_ALREADY_OPEN;
      WHEN 5
      THEN
         RAISE DUP_VAL_ON_INDEX;
      WHEN 6
      THEN
         RAISE INVALID_CURSOR;
      WHEN 7
      THEN
         RAISE INVALID_NUMBER;
      WHEN 8
      THEN
         RAISE LOGIN_DENIED;
      WHEN 9
      THEN
         RAISE NO_DATA_FOUND;
      WHEN 10
      THEN
         RAISE NOT_LOGGED_ON;
      WHEN 11
      THEN
         RAISE PROGRAM_ERROR;
      WHEN 12
      THEN
         RAISE ROWTYPE_MISMATCH;
      WHEN 13
      THEN
         RAISE SELF_IS_NULL;
      WHEN 14
      THEN
         RAISE STORAGE_ERROR;
      WHEN 15
      THEN
         RAISE SUBSCRIPT_BEYOND_COUNT;
      WHEN 16
      THEN
         RAISE SUBSCRIPT_OUTSIDE_LIMIT;
      WHEN 17
      THEN
         RAISE SYS_INVALID_ROWID;
      WHEN 18
      THEN
         RAISE TIMEOUT_ON_RESOURCE;
      WHEN 19
      THEN
         RAISE TOO_MANY_ROWS;
      WHEN 20
      THEN
         RAISE VALUE_ERROR;
      WHEN 21
      THEN
         RAISE ZERO_DIVIDE;
      ELSE
         RETURN v1;
   END CASE;
END;
/

DECLARE
   TYPE type1 IS TABLE OF NUMBER;

   col1   type1;
BEGIN
   FOR ii IN 1 .. 22
   LOOP
      BEGIN
         SELECT p1 (ii)
           BULK COLLECT INTO col1
           FROM DUAL;

         IF col1 (1) IS NULL
         THEN
            DBMS_OUTPUT.put_line (TO_CHAR (ii, '00') || ': NULL');
         ELSE
            DBMS_OUTPUT.put_line (TO_CHAR (ii, '00') || ': ' || col1 (1));
         END IF;
      EXCEPTION
         WHEN OTHERS
         THEN
            DBMS_OUTPUT.put_line (
                  TO_CHAR (ii, '00')
               || ': exception '
               || SQLCODE);
      END;
   END LOOP;
END;
/
0 голосов
/ 03 октября 2018

Я написал небольшой тестовый пример для вас, и исключение нужно проглотить внутри ty1 и не вызывать, потому что в противном случае выбор не завершился бы успешно:

create or replace function p1 (v1 number) return number
as
begin
if v1 = 1 then
return 1;
elsif v1 = 2 then
raise_application_error(-20010,'err 2');
else
raise_application_error(-20010,'err 3');
end if;
end;
/

declare
type type1 is table of number;
col1 type1;
begin
select p1(level) bulk collect into col1 from dual connect by level <=3;
end;
/

Результат:

Error report -
ORA-20010: err 2

Поэтому я предлагаю вам - если вы хотите оставаться рядом со своим решением - в месте, где вы обрабатываете исключение в ty1, вы записываете исключения в таблицу.Затем вы можете получить доступ к этой таблице, чтобы найти исключения, и вам не нужно перебирать всю коллекцию.Но, честно говоря, что не так с циклическим циклом в PL / SQL над коллекцией, все это в памяти?НТН

...