Опубликован: 25.09.2009 | Доступ: свободный | Студентов: 911 / 86 | Оценка: 3.72 / 2.78 | Длительность: 10:50:00
Лекция 4:

Эффективное программирование в PL/SQL. Встроенные подпрограммы, функции, процедуры и пакеты

< Лекция 3 || Лекция 4: 123 || Лекция 5 >

Создание тела и спецификации пакета

Пакет - это набор процедур, функций и переменных, объединенных с целью их совместного использования в приложении. При создании пакета создается интерфейсная часть - спецификация пакета и часть пакета, называемая "Телом". В нашем примере мы объединим все ранее созданные подпрограммы в единую структуру - пакет. Для начала мы создадим спецификацию пакета, в которой будут определены все подпрограммы.

Спецификация пакета

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 ".

  1. Находясь в Навигаторе Объектов, перейдите в узел "Параметры" и создайте два параметра.
  2. Установите для первого параметра следующие свойства:
    • Имя: old_value.
    • Тип данных: Varchar2.
    • Размер: 200.
  3. Установите для второго параметра следующие свойства:
    • Имя: block_item.
    • Тип данных: Varchar2.
    • Размер: 200.
  4. Определите на уровне блока триггер 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;
  5. Определите какой-нибудь триггер для отмены изменений в элементе и напишите в нем следующий код:

Триггер отмены

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.

< Лекция 3 || Лекция 4: 123 || Лекция 5 >
Константин Лукин
Константин Лукин

ошибка: FRM47337  Tree node label can not be null

при выполнении скрипта

DECLARE
 Itree ITEM;
 top_node Ftree.Node;
 new_node Ftree.Node;
 i_value VARCHAR2(30);
BEGIN
 Itree := Find_Item('tree_block.tree_item ');
 new_node := Ftree.Add_Tree_Node(Itree, Ftree.ROOT_NODE,
   Ftree.PARENT_OFFSET, Ftree.LAST_CHILD,
   Ftree.EXPANDED_NODE, i_value, NULL, i_value);
END;

Юлия Малыгина
Юлия Малыгина
приведена функция скрытия URL отчета и ее применение, но применения так и нет