Думаю, что наверняка кто-то из вас знаком с языками высокого уровня и с принципами объектно ориентированного программирования. Так вот. При определении пакетов можно применять очень интересный фокус под названием "переопределение функций и процедур" (overloaded). Например в C++ или C#, на котором я сейчас в основном пишу клиентские части для Oracle сервера, есть понятие "перегруженные функции". Когда в среде Visual Studio.NET, вы открываете скобку после определяющей сигнатуры функции то видите, то что изображено на рисунке:
Цифра 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! И с этим не поспорить. Но, имеются некоторые ограничения! Что поделать - такова жизнь!
PROCEDURE Add_One_Num(NM IN NUMBER); PROCEDURE Add_One_Num(NM OUT NUMBER);или
PROCEDURE Add_One_Num(A IN NUMBER); PROCEDURE Add_One_Num(B IN NUMBER);
FUNCTION Add_One_Num RETURN DATE; FUNCTION Add_One_Num RETURN VARCHAR;
PROCEDURE Add_One_Num(NM IN CHAR); PROCEDURE Add_One_Num(NM IN VARCHAR);
Но самое интересное, что на этапе компиляции вы не получите сообщений об ошибке, а вот при вызове такой функции возникнет ошибка PLS-307: too many declarations of "имя процедуры функции" match this call (этому вызову соответствует слишком много объявлений ... бла бла бла ) так что, будьте внимательны, переопределяя функции и процедуры в пакетах. :+)