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 |


