Не удается вызвать сообщение об ошибке приложения

#oracle #error-handling #plsql #oracle11g

#Oracle #обработка ошибок #plsql #oracle11g

Вопрос:

В целях отладки мне нужно создать сообщение уровня приложения на основе заданного флага. Вот код исключения

   EXCEPTION
    WHEN dml_errors THEN
      l_errors := SQL%BULK_EXCEPTIONS.COUNT;
      S_Publish('I', 'Number of statements that failed: ' || l_errors);
      FOR i IN 1..l_errors LOOP
         S_Publish('I', 'Error #' || TO_CHAR(i) || ' occurred during '|| 'iteration #' || SQL%BULK_EXCEPTIONS(i).ERROR_INDEX);
         S_Publish('I', 'Error message is ' || SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE));
         S_Publish('I', 'Failing Record ID is ' || sap_tbl_ins(SQL%BULK_EXCEPTIONS(i).ERROR_INDEX).DEVICE_PIN);
      END LOOP;
      IF g_app_error_flag THEN
        raise_application_error(-20707, 'Fatal Error: Replication script exceptions', TRUE);
      END IF;

    WHEN OTHERS THEN
      DBMS_OUTPUT.PUT_LINE('Error on record:' || l_zzman);
      S_Publish('I', 'SAP_EQUI Update: Failure processing record ' || l_zzman);
      S_Publish ('F');
      IF g_app_error_flag THEN
        raise_application_error(-20708, 'Fatal Error: Replication script exceptions', TRUE);
      END IF;
  

теперь, учитывая этот код, ошибка raise_application_error должна вызывать всякий раз, когда ** g_app_error_flag имеет значение true. Однако во всех случаях (я имею в виду среду тестирования, где я намеренно запускаю скрипт, добавляя некоторое ограничение в таблицу), все, что я вижу, это ошибка DML, т. Е.

 ORA-01403: no data found 
ORA-06512: at "DBNAME.PRODUCT_COPY_PACKAGE", line 1808 
ORA-24381: error(s) in array DML 
ORA-06512: at "DBNAME.PRODUCT_COPY_PACKAGE", line 84 
ORA-06512: at line 3 
  

не могли бы вы, ребята, подсказать, что происходит?

P.S:

вот определение для S_Publish. В S_Publish нет «повышения».

   PROCEDURE S_Publish (i_type IN VARCHAR2, 
                         i_msg IN VARCHAR2 DEFAULT NULL) IS
  BEGIN

    CASE

       WHEN i_type = 'G' THEN
         IF g_debug_flag
         THEN
           INSERT INTO logtable (tstamp,line) values (SYSDATE, i_msg);
           COMMIT;
           g_counter := 0;
         END IF;

       WHEN i_type = 'F' THEN
         g_err_code  := SQLCODE;
         g_err_msg   := TO_CHAR(g_err_code)||' '||SUBSTR(SQLERRM, 1, 100);
         INSERT INTO logtable (tstamp,line) values (SYSDATE, g_err_msg);
         COMMIT;

       WHEN i_type = 'I' THEN
         INSERT INTO logtable (tstamp,line) values (SYSDATE, i_msg);
         COMMIT;
         g_counter := 0;

    END CASE;


  END S_Publish;
  

После небольшой отладки это то, что я выяснил до сих пор. Я не знаю, что за eaosn стоит за этим

Итак, проблема в том, что программа завершается не раньше, чем заканчиваются ошибки печати, т. е. FOR i IN 1..l_errors LOOP . Программа завершается в END LOOP . Почему что-либо после этого не выполняется?

Комментарии:

1. Откуда вы знаете, что для этого g_app_error_flag установлено значение TRUE? И функционально, какой смысл проверять флаг ошибки в обработчике исключений? Конечно, тот факт, что вы находитесь в обработчике исключений, подразумевает, что приложение столкнулось с ошибкой. Наличие дополнительного логического флага, похоже, не добавляет никакой информации, а просто создает потенциал для дополнительных ошибок.

2. Согласен, но по соображениям производительности были введены флаги для уменьшения количества отладочных сообщений в рабочей среде. Истинный g_app_err_flag отправляется как значение TRUE при вызове скрипта. В скрипте, который устанавливает для g_app_error_flag значение true / false, нет логики .

Ответ №1:

Итак, проблема была в S_Publish . таблица, на которую оно ссылается, т.е. sap_tbl_ins является 0 основанной. SQL%BULK_EXCEPTIONS(i).ERROR_INDEX — это в основном номер итерации, когда произошел сбой. Таким образом, ссылка на индекс на основе 0 с числом вызывает исключение «array out of bound». Я только что разобрался с этим и изменил формулу на

 S_Publish('I', 'Failing Record ID is ' || sap_tbl_ins((SQL%BULK_EXCEPTIONS(i).ERROR_INDEX)-1).DEVICE_PIN);
  

и все работает нормально.

Ответ №2:

Поскольку мы не видим весь код, мы должны полагаться на вас, что когда вы намеренно вызываете сбой скрипта, добавляя некоторое ограничение в таблицу, тогда этот опубликованный вами блок исключений является активным. Итак, если этот блок вступает в действие, причиной того, что вы не видите свой «raise_application_error(-20707, …..» или второй с -20708, может быть то, что процедура «S_Publish» сама генерирует исключение. Это не будет перехвачено в том же блоке исключений, где они выполняются, если вы не окружите их дополнительным. чтобы проверить эту теорию, попробуйте временно удалить вызовы к нему и посмотреть, не появится ли у вас вызванная ошибка.

Комментарии:

1. ju8st обновил исходный тест с помощью определения S_PUBLISH . в S_PUBLISH нет исключения throw.

2. ему не обязательно явно генерировать исключение. в нем может произойти исключение во время его выполнения. но поскольку вы опубликовали его код, я не думаю, что он выдает исключение no_data_found, поскольку я не вижу в нем операторов select (и я полагаю, что после вставки в таблицу журнала не запускаются триггеры, в которых есть select, которые могут завершиться ошибкой). можете ли вы показать больше кода (возможно, используя pastebin.com ). особенно «DBNAME. PRODUCT_COPY_PACKAGE», строка 1808 «, поскольку там генерируется исключение. переносит ли ваш обработчик исключений место, где возникает исключение?

3. строка 1808 вставляет данные в таблицу с тремя значениями, скажем, col1, col2, col3. Однако таблица содержит 4 столбца, и для col4 существует ограничение not null . Из-за этого генерируется исключение. Вопрос в том, что это сгенерированное исключение было перехвачено в exception when others amp; но ошибка уровня приложения не возникает оттуда, хотя я вызываю ее явно оттуда.

4. и последнее: замените «raise_application_error» на некоторый DBMS_OUTPUT. ВВЕДИТЕ СТРОКУ_LINE по вашему выбору. вы видите, что оно отображается?

5. Итак, проблема в том, что программа завершается не раньше, чем заканчиваются ошибки печати, т. е. FOR i IN 1..l_errors LOOP . Программа завершается в END LOOP . Почему что-либо после этого не выполняется?

Ответ №3:

Хорошо, вопросы:

1) Какой код находится в / около строки 1808 в PRODUCT_COPY_PKG. Именно отсюда возникает первая ошибка.

2) Происходят ли вставки в logtable? (т. Е. — действительно ли выполняется этот блок исключений?)

3) Является ли вывод стека ошибок результатом ваших инструкций dbms_output? Или это дамп стека из Oracle во время выполнения?

Примечание по стилю: Я надеюсь, что S_PUBLISH определен с помощью PRAGMA AUTONOMOUS_TRANSACTION, в противном случае ваша фиксация может означать совершение частично завершенной транзакции, если ваш код был в процессе выполнения чего-либо, когда произошла ошибка..