FROM USER_OBJECTS

WHERE OBJECT_TYPE = 'PACKAGE BODY'

/

Получаем:

SQL> SELECT OBJECT_NAME, OBJECT_TYPE, STATUS

2 FROM USER_OBJECTS

3 WHERE OBJECT_TYPE = 'PACKAGE BODY'

4 /

OBJECT_NAME OBJECT_TYPE STATUS

-------------------------- ------------------ -------

TEST_PKG PACKAGE BODY INVALID

Оп! А, тело теперь недействительно! Исправляем ситуацию:

-- PACKAGE BODY test_pkg --

CREATE OR REPLACE PACKAGE BODY test_pkg IS

.

.

.

-- FUNCTION Mul_Two_Num --

FUNCTION Mul_Two_Num(A IN NUMBER, B IN NUMBER) RETURN NUMBER

IS

BEGIN

RETURN (A * B);

END Mul_Two_Num;

.

.

.

END test_pkg;

/

Добавляем функцию Mul_Two_Num к телу пакета и компилируем:

SQL> -- PACKAGE BODY test_pkg -- **************

SQL> CREATE OR REPLACE PACKAGE BODY test_pkg IS

2

.

.

.

33

34 -- FUNCTION Mul_Two_Num -- ****************************************

35 FUNCTION Mul_Two_Num(A IN NUMBER, B IN NUMBER) RETURN NUMBER

36 IS

37

38 BEGIN

39

40 RETURN (A * B);

41

42 END Mul_Two_Num;

.

.

.

58

59 END test_pkg;

60 /

Тело пакета создано.

Вот и все. Привожу текст в сокращенном виде дабы не занимать, лишнее место на Web - сервере. :) Вы можете проделать то же используя текст предыдущего шага. Главное не забывайте при изменении заголовка, если есть тело пакета хотя бы просто перекомпилировать его. В том случае, если вы добавили в заголовок не процедуру или функцию, а скажем переменную или курсор. Любое изменение заголовка делает тело пакет недействительным (invalid)! Просто перекомпилировать пакет можно так:

НЕ нашли? Не то? Что вы ищете?

ALTER PACKAGE test_pkg COMPILE

/

Получим:

SQL> ALTER PACKAGE test_pkg COMPILE

2 /

Пакет изменен.

Посмотрим еще раз на состояние тела пакета:

SELECT OBJECT_NAME, OBJECT_TYPE, STATUS

FROM USER_OBJECTS

WHERE OBJECT_TYPE = 'PACKAGE BODY'

/

Получаем:

SQL> SELECT OBJECT_NAME, OBJECT_TYPE, STATUS

2 FROM USER_OBJECTS

3 WHERE OBJECT_TYPE = 'PACKAGE BODY'

4 /

OBJECT_NAME OBJECT_TYPE STATUS

-------------------------- ------------------ -------

TEST_PKG PACKAGE BODY VALID

Вот собственно все и получилось! Попробуем, как себя чувствует новоиспеченная функция в пакете:

SET SERVEROUTPUT ON

DECLARE

BEGIN

test_pkg. Out_Screen(TO_CHAR(test_pkg. Min_Two_Num(10,4)));

test_pkg. Out_Screen(TO_CHAR(test_pkg. Add_Two_Num(5,2)));

test_pkg. Out_Screen(TO_CHAR(test_pkg. Add_Two_Num(test_pkg. FACTORIAL(5),4)));

test_pkg. Out_Screen(TO_CHAR(test_pkg. Mul_Two_Num(2,2)));

END;

/

Получаем:

SQL> SET SERVEROUTPUT ON

SQL>

SQL> DECLARE

2

3 BEGIN

4

5 test_pkg. Out_Screen(TO_CHAR(test_pkg. Min_Two_Num(10,4)));

6 test_pkg. Out_Screen(TO_CHAR(test_pkg. Add_Two_Num(5,2)));

7 test_pkg. Out_Screen(TO_CHAR(test_pkg. Add_Two_Num(test_pkg. FACTORIAL(5),4)));

8 test_pkg. Out_Screen(TO_CHAR(test_pkg. Mul_Two_Num(2,2)));

9

10 END;

11 /

6

7

124

4

Процедура PL/SQL успешно завершена.

Как в школьном курсе математики 2 * 2 всегда равно 4! (А не три и не пять это надо знать!) :) Теперь давайте рассмотрим, как же можно удалить пакет. Достаточно просто. Применить оператор DDL - DROP. Вот так:

DROP PACKAGE test_pkg

/

Получаем:

SQL> DROP PACKAGE test_pkg

2 /

Пакет удален.

При этом удаляется весь пакет! Больше ничего определять не нужно. Давайте убедимся в этом:

SELECT OBJECT_NAME, OBJECT_TYPE, STATUS

FROM USER_OBJECTS

WHERE OBJECT_TYPE IN ('PACKAGE', 'PACKAGE BODY')

/

Получаем:

SQL> SELECT OBJECT_NAME, OBJECT_TYPE, STATUS

2 FROM USER_OBJECTS

3 WHERE OBJECT_TYPE = 'PACKAGE BODY'

4 /

OBJECT_NAME OBJECT_TYPE STATUS

-------------------------- ------------------ -------

0 строк выбрано!

То есть делали мы делали и все бесполезно! Но, думаю только не для вас! А, это самое главное. Проделайте все еще раз и закрепите полученные навыки. :)

Шаг 99 - PL/SQL - Пакеты - Переопределение, функций и процедур

Думаю, что наверняка кто-то из вас знаком с языками высокого уровня и с принципами объектно ориентированного программирования. Так вот. При определении пакетов можно применять очень интересный фокус под названием "переопределение функций и процедур" (overloaded). Например в C++ или C#, на котором я сейчас в основном пишу клиентские части для Oracle сервера, есть понятие "перегруженные функции". Когда в среде Visual , вы открываете скобку после определяющей сигнатуры функции то видите, то что изображено на рисунке:

99_1.gif (3716 b)

Цифра 7 означает, что функция имеет семь перегруженных сигнатур. При выборе конкретной из них, срабатывает именно та, чья сигнатура определена в данный момент. Процедуры и функции внутри модуля (пакета) так же могут быть переопределены. То есть можно определить несколько процедур или функций с одним и тем же именем, но с разными параметрами. В PL/SQL - есть смысл применять данное свойство пакета, применительно к обработке объектов различных типов. Здесь как раз и просматривается, некое подобие или попытка привести PL/SQL - к объектно-ориентированной модели, применяя основные принципы ООП. Давайте практически попробуем это реализовать. Запишем такой заголовок пакета:

CREATE OR REPLACE PACKAGE TST_OVERLOAD IS

PROCEDURE Out_Screen(TOSC IN VARCHAR2);

FUNCTION Add_One_Num(NM IN NUMBER, BM IN NUMBER) RETURN NUMBER;

FUNCTION Add_One_Num(A IN INTEGER) RETURN NUMBER;

FUNCTION Add_One_Num(M IN NUMBER, K IN VARCHAR2) RETURN VARCHAR;

END TST_OVERLOAD;

/

Получаем после компиляции:

SQL> CREATE OR REPLACE PACKAGE TST_OVERLOAD IS

2

3 PROCEDURE Out_Screen(TOSC IN VARCHAR2);

4

5 FUNCTION Add_One_Num(NM IN NUMBER, BM IN NUMBER) RETURN NUMBER;

6

7 FUNCTION Add_One_Num(A IN INTEGER) RETURN NUMBER;

8

9 FUNCTION Add_One_Num(M IN NUMBER, K IN VARCHAR2) RETURN VARCHAR;

10

11 END TST_OVERLOAD;

12 /

Пакет создан.

В данном случае функция Add_One_Num имеет три типа инициализации. К стати обратите внимание на следующий интересный факт:

SELECT OBJECT_NAME, OBJECT_TYPE, STATUS

FROM USER_OBJECTS

WHERE OBJECT_TYPE = 'PACKAGE'

/

Получаем:

SQL> SELECT OBJECT_NAME, OBJECT_TYPE, STATUS

2 FROM USER_OBJECTS

3 WHERE OBJECT_TYPE = 'PACKAGE'

4 /

OBJECT_NAME OBJECT_TYPE STATUS

-------------------------- ------------------ -------

TST_OVERLOAD PACKAGE VALID

Оп! А поле STATUS показывает VALID! Но тела то, еще вообще нет! Где логика? Странный факт, но оставим это на совести Лари Элисона! :) Создаем тело пакета, чтобы успокоить совесть! Запишем:

-- PACKAGE BODY test_pkg --

CREATE OR REPLACE PACKAGE BODY TST_OVERLOAD IS

-- PROCEDURE Out_Screen --

PROCEDURE Out_Screen(TOSC IN VARCHAR2)

IS

BEGIN

DBMS_OUTPUT. enable;

DBMS_OUTPUT. put_line(TOSC);

END Out_Screen;

-- FUNCTION Add_One_Num -- One

FUNCTION Add_One_Num(NM IN NUMBER, BM IN NUMBER) RETURN NUMBER

IS

BEGIN

RETURN (NM + BM);

END Add_One_Num;

-- FUNCTION Add_One_Num -- Two

FUNCTION Add_One_Num(A IN INTEGER) RETURN NUMBER

IS

BEGIN

RETURN (A + 20);

END Add_One_Num;

-- FUNCTION Add_One_Num --

FUNCTION Add_One_Num(M IN NUMBER, K IN VARCHAR2) RETURN VARCHAR

IS

BEGIN

RETURN (TO_CHAR(M + TO_NUMBER(K)));

END Add_One_Num;

END TST_OVERLOAD;

/

После компиляции получаем:

SQL> CREATE OR REPLACE PACKAGE BODY TST_OVERLOAD IS

2

3 -- PROCEDURE Out_Screen --

4 PROCEDURE Out_Screen(TOSC IN VARCHAR2)

5 IS

6

7 BEGIN

8

9 DBMS_OUTPUT. enable;

10 DBMS_OUTPUT. put_line(TOSC);

11

12 END Out_Screen;

13

14 -- FUNCTION Add_One_Num -- One

15 FUNCTION Add_One_Num(NM IN NUMBER, BM IN NUMBER) RETURN NUMBER

16 IS

17

18 BEGIN

19

20 RETURN (NM + BM);

21

22 END Add_One_Num;

23

24 -- FUNCTION Add_One_Num -- Two

25 FUNCTION Add_One_Num(A IN INTEGER) RETURN NUMBER

26 IS

27

28 BEGIN

29

30 RETURN (A + 20);

31

32 END Add_One_Num;

33

34 -- FUNCTION Add_One_Num --

35 FUNCTION Add_One_Num(M IN NUMBER, K IN VARCHAR2) RETURN VARCHAR

36 IS

37

38 BEGIN

39

40 RETURN (TO_CHAR(M + TO_NUMBER(K)));

41

42 END Add_One_Num;

43

44 END TST_OVERLOAD;

45 /

Тело пакета создано.

Чему мы и радуемся! Наконец получили пакет с переопределенными функциями. Теперь можно проверить как ведет себя наша немного комическая функция Add_One_Num! :) Хотя это собственно не важно, главное чтобы вы хорошо усвоили, как это все работает. Итак, запишем анонимный блок:

SET SERVEROUTPUT ON

DECLARE

BEGIN

TST_OVERLOAD. Out_Screen(TO_CHAR( TST_OVERLOAD. Add_One_Num(TST_OVERLOAD. Add_One_Num(6),

TO_CHAR(TST_OVERLOAD. Add_One_Num(4, '7')))));

TST_OVERLOAD. Out_Screen(TO_CHAR(TST_OVERLOAD. Add_One_Num(2,2)));

END;

/

Получаем:

SQL> SET SERVEROUTPUT ON

SQL>

SQL> DECLARE

2

3 BEGIN

4

5 TST_OVERLOAD. Out_Screen(TO_CHAR( TST_OVERLOAD. Add_One_Num(TST_OVERLOAD. Add_One_Num(6),

6 TO_CHAR(TST_OVERLOAD. Add_One_Num(4, '7')))));

7 TST_OVERLOAD. Out_Screen(TO_CHAR(TST_OVERLOAD. Add_One_Num(2,2)));

8

9 END;

10 /

37

4

Процедура PL/SQL успешно завершена.

И снова арифметика за первый класс торжествует 2 плюс 2 равно 4! И с этим не поспорить. Но, имеются некоторые ограничения! Что поделать - такова жизнь!

1.  Нельзя переопределить процедуру или функцию, если их сигнатуры отличаются только именами или видами.
Например:

2.  PROCEDURE Add_One_Num(NM IN NUMBER);

3.  PROCEDURE Add_One_Num(NM OUT NUMBER);

или

PROCEDURE Add_One_Num(A IN NUMBER);

PROCEDURE Add_One_Num(B IN NUMBER);

4.  Нельзя переопределить процедуру или функцию, если их сигнатуры отличаются лишь типами возвращаемых ими данных.
Например:

5.  FUNCTION Add_One_Num RETURN DATE;

6.  FUNCTION Add_One_Num RETURN VARCHAR;

7.  Типы параметров процедур или функций должны принадлежать различным семействам типов. Например, CHAR и VARCHAR это одно и тоже по этому нельзя переопределять процедуры вот так:

Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5 6 7 8