Павел Лузанов

Oracle Forms. Как избежать появления "FRM-40401: Нет изменений для сохранения."


При сохранении данных (выполнение COMMIT в триггере или нажатие пользователем на [Сохранить]), Oracle Forms иногда выдает ошибку FRM-40401, но изменения при этом сохраняются.

При выполнении POST может появиться похожее сообщение "FRM-40405: Нет обновлений, кот. следует принять."

Как избежать появления подобных сообщений?

Ответ на этот вопрос необходимо разбить на две части.
Во-первых, нужно разобраться в причинах появления этого сообщения.
И во-вторых, рассмотреть возможные способы "борьбы" с появлением подобных, впрочем как и любых других, сообщений Oracle Forms.

Итак.

Причины появления FRM-40401

Причину появления любого системного сообщения, а также возможные действия, которые нужно в связи с этим предпринять, можно получить в справочной системе Oracle Forms.

Если обратиться к этой системе, то для FRM-40401 можно обнаружить (в моей интерпретации) следующее:
Причина (Cause) Отсутствуют записи, добавленные или измененные с момента последнего применения(POST) или сохранения(COMMIT).
Действия (Action) Действия не требуются.

То есть, с момента последнего сохранения изменений, записи в блоках данных (блоки со свойством Database Data Block = Yes) не изменялись и Forms-у не нужно генерировать команды INSERT, UPDATE, DELETE, о чем он нам и сообщает.

Я специально выделил "записи в блоках данных", т.к. отсутствие изменений именно в них имеется ввиду в тексте сообщения об ошибке FRM-40401.

Но имеется еще один тип изменений, которые возможно произвести в Oracle Forms. Можно напрямую записать команды INSERT, UPDATE, DELETE в триггеры формы, не участвующие в процессе сохранения данных, скажем в WHEN-BUTTON-PRESSED. Также, из таких триггеров можно вызывать хранимые процедуры, выполняющие изменения в базе данных.

Более того, именно такого рода изменения вы и пытаетесь сохранить, иначе, сообщение FRM-40401 и не появлялось бы.

Изменение формулировки исходного вопроса

На этой стадии ответа, с учетом изложенного выше, позвольте переформулировать исходный вопрос:

"Так почему же появляется это сообщение. Мы сделали напрямую изменения в базе данных и тут же пытаемся их сохранить. Мы просто выполняем COMMIT, нам не нужно обрабатывать изменения в блоках данных."

Когда Oracle Forms встречает в тексте триггера COMMIT, он автоматически заменяет эту команду на встроенную подпрограмму COMMIT_FORM (также как и ROLLBACK на CLEAR_FORM).

COMMIT_FORM же, в свою очередь, не просто выполняет COMMIT. Эта процедура предварительно проверяет статус формы и при необходимости выполнения изменений, для каждого блока данных формирует и выполняет требуемые команды DELETE, UPDATE, INSERT (кстати, именно в таком порядке).
Если изменений не было - получаем FRM-40401.

И только после этого выпоняется "настоящий" COMMIT, сохраняющий, в том числе, и изменения в форме сделанные напрямую.

Встречный вопрос.
А теперь попробуйте объяснить, почему при выполнении FORMS_DDL('COMMIT'), взамен просто COMMIT , и изменения сохраняются, и FRM-40401 не появляется.

Способы "борьбы" с системными сообщениями Oracle Forms

Разработчики продукта Oracle Forms не рекомендуют производить прямые изменения в базе данных в триггерах не задействованных при сохранении данных. Однако, нужно признать, что необходимость в них все-таки бывает, и поэтому нам нужны способы "избавления" от появления этого сообщения.

Давайте же их рассмотрим.
Помимо частного случая с FORMS_DDL('COMMIT') (частного для FRM-40401), существует два способа обработки любых сообщений Oracle Forms.

Предостережение об использовании FORMS_DDL('COMMIT').
Ни в коем случае не используйте эту команду, без полного понимания того, что она делает!!! Например, нужно точно понимать отличия FORMS_DDL('COMMIT') от процедуры commit2 приведенной ниже

Использование SYSTEM.MESSAGE_LEVEL

Каждому системному сообщению назначен, так называемый, уровень серьезности (severity level). Всего существует 6 уровней: 5, 10, 15, 20, 25, >25

Узнать уровень конкретного сообщения можно в справочной системе. Для этого откройте Help->Form Builder Help Topics (Ctrl+H) и на закладке 'Поиск' введите, например, 'FRM-40401'.

Помимо упомянутых выше Причины(Cause) и Действий(Action), здесь можно увидеть Уровень(Level) и Тип сообщения(Type) (тип нам понадобиться позже).

Теперь о системной переменной SYSTEM.MESSAGE_LEVEL.
Если в процессе работы формы, требуется вывести сообщение, то оно будет выведено только в том случае, если уровень этого сообщения больше чем значение SYSTEM.MESSAGE_LEVEL. В противном случае, сообщение будет проигнорировано.

По умолчанию, значение SYSTEM.MESSAGE_LEVEL равно '0', и это значит, что Oracle Forms будет выводить любые сообщения.

Исходя из списка возможных уровней, мы имеем 6 значений, которые имеет смысл присваивать переменной SYSTEM.MESSAGE_LEVEL (одна из немногих системных переменных, которым можно присваивать значения): 0, 5, 10, 15, 20, 25

Присвоение переменной SYSTEM.MESSAGE_LEVEL значения 10 будет означать, что все сообщения, имеющие уровень 5 или 10, больше выводиться не будут.

Нет никакого смысла, хотя и не будет ошибкой, присваивать этой переменной значения типа 12 или 14. Можно обойтись 10 - эффект тот же (Строго говоря, ошибкой будет присвоение значения не из диапазона 0 .. 25).

Сообщения имеющие уровень '>25' подавить нельзя. Это, как правило, сообщения о грубых ошибках в программе.

Имея ввиду всё сказанное выше, а также информацию о том, что уровень сообщения FRM-40401 равен 5, можно написать простую процедуру, которая будет сохранять изменения в форме и при этом "не ругаться":

PROCEDURE commit2
IS
BEGIN
   IF TO_NUMBER(NAME_IN('SYSTEM.MESSAGE_LEVEL')) < 5
   THEN
      COPY ('5', 'SYSTEM.MESSAGE_LEVEL');
      COMMIT;
      COPY ('0', 'SYSTEM.MESSAGE_LEVEL');
   ELSE
      COMMIT;
   END IF;
END commit2;

Теперь после выполнения прямых изменений в форме вместо COMMIT можно использовать commit2

Примечание.
Это лишь образец процедуры. Сюда же можно добавить выполнение не только COMMIT, но и POST, а также проверку статуса завершения.

Использование триггеров ON-ERROR, ON-MESSAGE

Этот способ позволяет не просто подавить сообщение, он позволяет его перехватить и выполнить любые требуемые действия (в том числе и ничего не делать, если нам всё-таки нужно подавить сообщение). Некий аналог секции EXCEPTION языка PL/SQL.

Выше уже упоминалось, что для каждого сообщения в справочной системе определён тип. Существует два типа сообщений:

Для перехвата системных сообщений Oracle Forms используются триггеры: ON-ERROR для сообщений об ошибке и ON-MESSAGE - для информационных сообщений.

Возвращаясь к FRM-40401, видно что это сообщение об ошибке, следовательно для его перехвата нужно использовать триггер ON-ERROR:

/* 40401 возникает при COMMIT, 40405 - при POST */
IF ERROR_CODE IN (40401, 40405) 
THEN
   NULL; -- либо требуемые действия
ELSE
   MESSAGE (ERROR_TYPE || '-' || ERROR_CODE || ': ' || ERROR_TEXT);
   RAISE FORM_TRIGGER_FAILURE;
END IF;

Фраза ELSE в этом триггере выполняет стандартные действия Oracle Forms для всех прочих сообщений об ошибках.

Ну и не нужно забывать, что триггеры ON-ERROR и ON-MESSAGE могут быть определены на всех трех уровнях: элемента, блока, формы.


11 Июня 2003г.

Hosted by www.Geocities.ws

1