CREATE OR REPLACE FUNCTION BOOL_TO_CHAR(INBL IN BOOLEAN) RETURN VARCHAR2

IS

OUT_ST VARCHAR2(5);

BEGIN

IF (INBL) THEN

OUT_ST := 'TRUE';

ELSIF (NOT INBL) THEN

OUT_ST := 'FALSE';

ELSE

OUT_ST := 'NULL';

END IF;

RETURN(OUT_ST);

END BOOL_TO_CHAR;

/

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

SQL> CREATE OR REPLACE FUNCTION BOOL_TO_CHAR(INBL IN BOOLEAN) RETURN VARCHAR2

2 IS

3

4 OUT_ST VARCHAR2(5);

5

6 BEGIN

7

8 IF (INBL) THEN

9 OUT_ST := 'TRUE';

10 ELSIF (NOT INBL) THEN

11 OUT_ST := 'FALSE';

12 ELSE

13 OUT_ST := 'NULL';

14 END IF;

15

16 RETURN(OUT_ST);

17

18 END BOOL_TO_CHAR;

19 /

Функция создана.

Теперь попробуем применить ее на практике. Запишем такой анонимный блок:

SET SERVEROUTPUT ON

DECLARE

BEGIN

DBMS_OUTPUT. enable;

DBMS_OUTPUT. put_line(BOOL_TO_CHAR(TRUE));

DBMS_OUTPUT. put_line(BOOL_TO_CHAR(FALSE));

DBMS_OUTPUT. put_line(BOOL_TO_CHAR(NULL));

END;

/

Получаем:

SQL> SET SERVEROUTPUT ON

SQL> DECLARE

2

3 BEGIN

4

5 DBMS_OUTPUT. enable;

6 DBMS_OUTPUT. put_line(BOOL_TO_CHAR(TRUE));

7 DBMS_OUTPUT. put_line(BOOL_TO_CHAR(FALSE));

8 DBMS_OUTPUT. put_line(BOOL_TO_CHAR(NULL));

9

10 END;

11 /

TRUE

FALSE

NULL

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

Как видите, наша функция BOOL_TO_CHAR вызвана внутри определения DBMS_OUTPUT. put_line(..), так обычно и происходит. Хорошо видно, что мы получили строки, передав булевы значения.

Теперь давайте поговорим об операторе RETURN. Этот оператор возвращает значение функции, приводя его к типу возвращаемого функцией.

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

------------ RETURN (значение) ------------------------------

Где значение - это то что и возвращает функция. Здесь скобки "()" - это только стиль при написании функций, для того чтобы было немного понятнее. Операторов RETURN в функции может быть несколько, при этом первый из них, завершит ее работу и вернет управление в вызывающую процедуру! Давайте напишем еще одну функцию преобразования BOOLEAN в VARCHAR2, но при этом используем немного другую логику:

CREATE OR REPLACE FUNCTION BOOL_TO_CHARTWO(INBL IN BOOLEAN) RETURN VARCHAR2

IS

BEGIN

IF (INBL) THEN

RETURN('TRUE');

ELSIF (NOT INBL) THEN

RETURN('FALSE');

ELSE

RETURN('NULL');

END IF;

END BOOL_TO_CHARTWO;

/

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

SQL> CREATE OR REPLACE FUNCTION BOOL_TO_CHARTWO(INBL IN BOOLEAN) RETURN VARCHAR2

2 IS

3

4 BEGIN

5

6 IF (INBL) THEN

7 RETURN('TRUE');

8 ELSIF (NOT INBL) THEN

9 RETURN('FALSE');

10 ELSE

11 RETURN('NULL');

12 END IF;

13

14 END BOOL_TO_CHARTWO;

15 /

Функция создана.

Хорошо видно, что мы заменили промежуточную переменную и применили три оператора RETURN. В данном случае это будет то же, что и первая функция хоть и немного в другом контексте. Запишем вот такой анонимный блок:

SET SERVEROUTPUT ON

DECLARE

BEGIN

DBMS_OUTPUT. enable;

DBMS_OUTPUT. put_line(BOOL_TO_CHARTWO(TRUE));

DBMS_OUTPUT. put_line(BOOL_TO_CHARTWO(FALSE));

DBMS_OUTPUT. put_line(BOOL_TO_CHARTWO(NULL));

END;

/

Получаем:

SQL> SET SERVEROUTPUT ON

SQL>

SQL> DECLARE

2

3 BEGIN

4

5 DBMS_OUTPUT. enable;

6 DBMS_OUTPUT. put_line(BOOL_TO_CHARTWO(TRUE));

7 DBMS_OUTPUT. put_line(BOOL_TO_CHARTWO(FALSE));

8 DBMS_OUTPUT. put_line(BOOL_TO_CHARTWO(NULL));

9

10 END;

11 /

TRUE

FALSE

NULL

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

Что и требовалось доказать! Так же смею заметить, что в PL/SQL с успехом можно применять рекурсию. Рекурсивные вызовы иногда делают код меньше, но запутаннее! Приведу один пример расчета факториала числа, это я подглядел у Билла Гейтса в его MSDN и переложил на PL/SQL, не все же ему таскать у других! :) Итак:

CREATE OR REPLACE FUNCTION FACTORIAL(NUM IN NUMBER) RETURN NUMBER

IS

BEGIN

IF (NUM <=1) THEN

RETURN (NUM);

ELSE

RETURN (NUM * FACTORIAL(NUM-1));

END IF;

END FACTORIAL;

/

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

SQL> CREATE OR REPLACE FUNCTION FACTORIAL(NUM IN NUMBER) RETURN NUMBER

2 IS

3

4 BEGIN

5

6 IF (NUM <=1) THEN

7 RETURN (NUM);

8 ELSE

9 RETURN (NUM * FACTORIAL(NUM-1));

10

11 END IF;

12

13 END FACTORIAL;

14 /

Функция создана.

Запишем анонимный блок для трех значений - вот такой:

SET SERVEROUTPUT ON

DECLARE

BEGIN

DBMS_OUTPUT. enable;

DBMS_OUTPUT. put_line(TO_CHAR(FACTORIAL(5)));

DBMS_OUTPUT. put_line(TO_CHAR(FACTORIAL(7)));

DBMS_OUTPUT. put_line(TO_CHAR(FACTORIAL(12)));

END;

/

Получаем:

SQL> SET SERVEROUTPUT ON

SQL>

SQL> DECLARE

2

3 BEGIN

4

5 DBMS_OUTPUT. enable;

6 DBMS_OUTPUT. put_line(TO_CHAR(FACTORIAL(5)));

7 DBMS_OUTPUT. put_line(TO_CHAR(FACTORIAL(7)));

8 DBMS_OUTPUT. put_line(TO_CHAR(FACTORIAL(12)));

9

10 END;

11 /

120

5040

479001600

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

Ух, ты! Работает! Привет Биллу! Получили три значения факториала чисел 5, 7, 12. Проверьте правильно или нет?

Вот собственно так пишутся функции. Хотите задание? А вот - в PL/SQL нет функции сложения и вычитания одного времени суток и другого! Напишите функции, которые, например, складывают и вычитают, скажем, 10:34 и 5:08! Я такое делал. Интересно, что у вас получится? Пробуйте!

Шаг 94 - PL/SQL - Функции и процедуры - размещение

Мы с вами уже многое знаем о процедурах и функциях, вот теперь давайте поговорим о том, где находятся и хранятся откомпилированные процедуры и функции. После того, как команда CREATE OR REPLACE создает процедуру или функцию, она сразу сохраняется в БД, в скомпилированной форме, которая называется p-кодом (p-code). В p-коде содержатся все обработанные ссылки подпрограммы, а исходный текст преобразован, в вид удобный для чтения системой поддержки PL/SQL. При вызове хранимой процедуры p-код считывается с диска и выполняется. Собственно сам P-код аналогичен объектному коду генерируемому компиляторами языков программирования высокого уровня. В P-коде содержатся обработанные ссылки на объекты (это свойство ранней привязки переменных, о которой мы говорили с вами ранее) по этому выполнение P-кода является сравнительно не дорогой (нересурсоемкой) операцией. Да к слову напомню, что удалить код процедуры или функции из вашей БД (схемы) можно применив, оператор DROP - вот таким образом (в шаге 87 мы уже это делали):

---- DROP PROCEDURE имя_процедуры ------------------------

---- DROP FUNCTION имя_функции ---------------------------

Теперь давайте вспомним каким образом можно получить информацию о наличии процедур и их работоспособности. Самое простое это выполнить такой запрос к системному представлению USER_OBJECTS вот так:

SELECT OBJECT_NAME, OBJECT_TYPE, STATUS

FROM USER_OBJECTS

/

В моем случае получилось следующее:

SQL> SELECT OBJECT_NAME, OBJECT_TYPE, STATUS

2 FROM USER_OBJECTS

3 /

OBJECT_NAME OBJECT_TYPE STATUS

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

BOOL_TO_CHAR FUNCTION VALID

BOOL_TO_CHARTWO FUNCTION VALID

BOYS TABLE VALID

CUSTOMERS TABLE VALID

FACTORIAL FUNCTION VALID

GIRLS TABLE VALID

OFFICES TABLE VALID

ORDERS TABLE VALID

PRODUCTS TABLE VALID

PTEST PROCEDURE VALID

SALESREPS TABLE VALID

SYS_C003505 INDEX VALID

SYS_C003506 INDEX VALID

SYS_C003507 INDEX VALID

SYS_C003511 INDEX VALID

SYS_C003512 INDEX VALID

SYS_C003513 INDEX VALID

SYS_C003515 INDEX VALID

TESTINOUT PROCEDURE VALID

TESTOUT PROCEDURE VALID

OBJECT_NAME OBJECT_TYPE STATUS

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

TESTPRG PROCEDURE VALID

TESTPRGTWO PROCEDURE VALID

TESTPRM PROCEDURE VALID

TEST_POZ PROCEDURE VALID

24 строк выбрано.

Я включил только три столбца представления, которые дают основную информацию, но если хотите можете использовать все столбцы. Хорошо видно, что у нас с вами все объекты имеют статус VALID, то есть исправны. А, вот как, например увидеть текст хранимой процедуры или функции, для этого используйте системное представление USER_SOURCE. Давайте к примеру выведем текст функции из прошлого шага - FACTORIAL:

SELECT * FROM USER_SOURCE

WHERE NAME = 'FACTORIAL'

/

Получаем:

SQL> SELECT * FROM USER_SOURCE

2 WHERE NAME = 'FACTORIAL'

3 /

NAME TYPE LINE TEXT

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

FACTORIAL FUNCTION 1 FUNCTION FACTORIAL(NUM IN NUMBER) RETURN NUMBER

FACTORIAL FUNCTION 2 IS

FACTORIAL FUNCTION 3

FACTORIAL FUNCTION 4 BEGIN

FACTORIAL FUNCTION 5

FACTORIAL FUNCTION 6 IF (NUM <=1) THEN

FACTORIAL FUNCTION 7 RETURN (NUM);

FACTORIAL FUNCTION 8 ELSE

FACTORIAL FUNCTION 9 RETURN (NUM * FACTORIAL(NUM-1));

FACTORIAL FUNCTION 10

FACTORIAL FUNCTION 11 END IF;

FACTORIAL FUNCTION 12

FACTORIAL FUNCTION 13 END FACTORIAL;

13 строк выбрано.

Вот и содержимое самой функции! Все можно найти в системных представлениях. А, что если при создании функции или процедуры происходит ошибка компиляции? Давайте рассмотрим такой вариант. Создадим процедуру намеренно с ошибкой:

CREATE OR REPLACE PROCEDURE TESTERR(NUM IN NUMBER)

IS

K NUMBER;

BEGIN

K := NUM

END TESTERR;

/

Получаем:

SQL> CREATE OR REPLACE PROCEDURE TESTERR(NUM IN NUMBER)

2 IS

3

4 K NUMBER;

5

6 BEGIN

7

8 K := NUM

9

10 END TESTERR;

11 /

Предупреждение: Процедура создана с ошибками компиляции.

Правильно, в данном случае мы забыли поставить ";" после завершения строки K := NUM. Вот теперь давайте дадим такой запрос:

SELECT OBJECT_NAME, OBJECT_TYPE, STATUS

FROM USER_OBJECTS

WHERE STATUS = 'INVALID'

/

Получаем:

SQL> SELECT OBJECT_NAME, OBJECT_TYPE, STATUS

2 FROM USER_OBJECTS

3 WHERE STATUS = 'INVALID'

4 /

OBJECT_NAME OBJECT_TYPE STATUS

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

TESTERR PROCEDURE INVALID

Странно, процедура вроде бы создана, ее p-код присутствует, но она не исправна! Попробуем вызвать ее:

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