ошибка: FRM47337 Tree node label can not be null при выполнении скрипта DECLARE |
Эффективное программирование в PL/SQL. Встроенные подпрограммы, функции, процедуры и пакеты
Создание тела и спецификации пакета
Пакет - это набор процедур, функций и переменных, объединенных с целью их совместного использования в приложении. При создании пакета создается интерфейсная часть - спецификация пакета и часть пакета, называемая "Телом". В нашем примере мы объединим все ранее созданные подпрограммы в единую структуру - пакет. Для начала мы создадим спецификацию пакета, в которой будут определены все подпрограммы.
PACKAGE "MY_PKG" AS function HOW_DAY (dai varchar2) return number; function DAYS_IN_month (val IN date) return number; function first_day(val date) return date; PROCEDURE N_Table (tab_name varchar2, n NUMBER); PROCEDURE DONT_DELETE_LAST_RECORD; END; Тело пакета PACKAGE BODY "MY_PKG" AS function First_day (val date) return date is begin return to_date('01'||substr(val, 3)); end First_day; FUNCTION DAYS_IN_MONTH ( val IN DATE ) RETURN NUMBER IS LN number := 0 ; s number:=0; BEGIN FOR i IN 1..31 LOOP IF TO_CHAR(to_date(i||substr(val,3)), 'DAY') = 'SUNDAY' THEN LN := LN+ 1 ; s:=ln; END IF ; END LOOP ; RETURN s ; END ; FUNCTION "HOW_DAY"( dai varchar2) return number as val number; begin Select Count (a.L_day) INTO val From (Select Rtrim (To_char (To_date ( Rownum|| '-'||To_char (Sysdate, 'mon-yy')), 'DAY' )) As L_day From user_all_tables Where Rownum Between 1 And To_char (Last_day (Sysdate), 'DD')) a Where a.L_day = upper(dai); RETURN val; END; PROCEDURE "N_Table" (tab_name varchar2, n NUMBER) IS my_ddl VARCHAR2(2000); BEGIN my_ddl := 'create table '||tab_name||'(COL1 NUMBER'; FOR I in 2..N LOOP my_ddl := my_ddl||',COL'||TO_CHAR(i)||' NUMBER'; END LOOP; my_ddl := my_ddl||')'; Forms_DDL(my_ddl); IF NOT Form_Success THEN Message ('Таблица не создана'); ELSE Message ('Таблица создана'); END IF; END; PROCEDURE DONT_DELETE_LAST_RECORD IS BEGIN IF :System.Last_Record = 'TRUE' AND :System.Cursor_Record ='1' THEN Message('Последняя запись не может быть удалена'); ELSE Delete_Record; END IF; END; END;
Вы можете расширять пакет, добавляя в него новые процедуры и функции.
Обращение к подпрограммам пакета
Для того чтобы вызвать подпрограмму пакета, необходимо перед вызовом подпрограммы указать имя пакета.
DECLARE Vdmonth number; Vfday varchar2(20); BEGIN Message(my_pkg.HOW_DAY ('FRIDAY') return number; Vdmonth:= my_pkg.DAYS_IN_MONTH (sysdate); Vfday:= my_pkg.first_day(sysdate); my_pkg.N_Table ('test',3); my_pkg.DONT_DELETE_LAST_RECORD; END;
Создание эффекта отмены действий в элементе
В Oracle Forms, если пользователь вошел в запись и изменил ее значение, он не может отменить свое действие, не перезапросив данные.
Перезапросить данные - хоть и самый простой способ, но не самый лучший и не единственный выход из ситуации. Рассмотрим еще два способа:
- Хранение первоначального значения в параметре.
- Использование константы DATBASE_VALUE.
Хранение первоначального значения в параметре
Для того чтобы выполнить это упражнение, создайте или откройте любую существующую форму и сохраните ее под именем " Undo ".
- Находясь в Навигаторе Объектов, перейдите в узел "Параметры" и создайте два параметра.
- Установите для первого параметра следующие свойства:
- Имя: old_value.
- Тип данных: Varchar2.
- Размер: 200.
- Установите для второго параметра следующие свойства:
- Имя: block_item.
- Тип данных: Varchar2.
- Размер: 200.
- Определите на уровне блока триггер WHEN-NEW-ITEM-INSTANCE и напишите в теле триггера нижеприведенный код:
WHEN-NEW-ITEM-INSTANCE :parameter.old_value:=:system.current_value; IF Get_Item_Property(:system.current_item, ITEM_TYPE) IN ('DISPLAY ITEM', 'CHECKBOX', 'LIST', 'RADIO GROUP', 'TEXT ITEM') AND Get_Item_Property ((:system.current_item, BASE_TABLE) = 'TRUE' THEN :parameter.block_item:=:system.trigger_item; ELSE :parameter.block_item:=null; END IF;
- Определите какой-нибудь триггер для отмены изменений в элементе и напишите в нем следующий код:
Триггер отмены
DECLARE Cur_val varchar2(200):=:system.current_value; BEGIN IF :SYSTEM.RECORD_STATUS = 'CHANGED' THEN IF :parameter.old_value<>cur_val AND :parameter.block_item IS NOT NULL THEN COPY(:parameter.old_value, :parameter.block_item) END IF; END IF; END;
Запустите форму для просмотра результатов, попробуйте изменить значение и вернуть предыдущее. Этот пример действует только в пределах текущего элемента, то есть вы можете отменить изменение только в одном элементе.
Процедура UNDO
Процедура UNDO предназначена для отмены всех сделанных изменений в блоке без перезапроса данных. В этой процедуре определяется статус записи, и если она находится в режиме редактирования, то ее значение будет восстановлено на первоначальное.
PROCEDURE Undo IS V_Block VARCHAR2 (30) := :SYSTEM.CURSOR_BLOCK; V_Field VARCHAR2 (61); V_Item VARCHAR2 (61); BEGIN Validate (Item_Scope); IF :SYSTEM.RECORD_STATUS = 'CHANGED' THEN V_Field := Get_Block_Property (V_Block, FIRST_ITEM); V_Item := V_Block || '.' || V_Field; WHILE V_Field IS NOT NULL LOOP IF Get_Item_Property (V_Item, ITEM_TYPE) IN ('DISPLAY ITEM', 'CHECKBOX', 'LIST', 'RADIO GROUP', 'TEXT ITEM') AND Get_Item_Property (V_Item, BASE_TABLE) = 'TRUE' THEN COPY (Get_Item_Property (V_Item, DATABASE_VALUE), V_Item); END IF; V_Field := Get_Item_Property (V_Item, NextItem); V_Item := V_Block || '.' || V_Field; END LOOP; END IF; END;Листинг 4.4. Процедура "UNDO" (вы можете использовать эту в процедуру в триггере отмены действий)
Запустите форму для просмотра результатов, попробуйте изменить значение нескольких элементов, затем попробуйте вернуть им первоначальные значения с помощью процедуры UNDO.