|
ошибка: 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.