#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, в противном случае ваша фиксация может означать совершение частично завершенной транзакции, если ваш код был в процессе выполнения чего-либо, когда произошла ошибка..