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 , вы открываете скобку после определяющей сигнатуры функции то видите, то что изображено на рисунке:

Цифра 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 |


