Мы с вами уже многое знаем о процедурах и функциях, вот теперь давайте поговорим о том, где находятся и хранятся откомпилированные процедуры и функции. После того, как команда 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-код присутствует, но она не исправна! Попробуем вызвать ее:
EXEC TESTERR;
Ответ будет таким:
SQL> EXEC TESTERR; BEGIN TESTERR; END; * ошибка в строке 1: ORA-06550: Строка 1, столбец 7: PLS-00905: неприемлемый объект MILLER.TESTERR ORA-06550: Строка 1, столбец 7: PL/SQL: Statement ignored
Все верно - процедура с ошибками! Так вот, я морочил вам голову, только по тому, чтобы вы ясно представляли себе куда бежать, если что-то не выходит! А вот теперь повторим компиляцию:
. . 7 8 K := NUM 9 10 END TESTERR; 11 / Предупреждение: Процедура создана с ошибками компиляции.
И дадим такую строку:
SHOW ERRORS
Получаем:
SQL> SHOW ERRORS Ошибки для PROCEDURE TESTERR: LINE/COL ERROR -------- ----------------------------------------------------------------- 10/1 PLS-00103: Встретился символ "END" в то время как ожидалось одно из следующих: . ( * @ % & = - + ; < / > at in is mod not rem <an exponent (**)> <> or != or ~= >= <= <> and or like between || Символ ";" заменен на "END", чтобы можно было продолжать.
Вот теперь кое, кое что стало яснее. Ошибка PLS-00103 означает наличие незавершенного оператора, команда SHOW ERRORS, считывает данные из системного представления USER_ERRORS, вот его описание:
SQL> DESC USER_ERRORS Имя Пусто? Тип --------- -------- ---------------------------- NAME NOT NULL VARCHAR2(30) TYPE VARCHAR2(12) SEQUENCE NOT NULL NUMBER LINE NOT NULL NUMBER POSITION NOT NULL NUMBER TEXT NOT NULL VARCHAR2(4000)
Теперь давайте дадим вот такой запрос:
SELECT NAME, TEXT FROM USER_ERRORS /
Вот и содержимое:
SQL> SELECT NAME, TEXT FROM USER_ERRORS 2 / NAME TEXT ------- --------------------------------------------------------------------------- TESTERR PLS-00103: Встретился символ "END" в то время как ожидалось одно из следующих: . ( * @ % & = - + ; < / > at in is mod not rem <an exponent (**)> <> or != or ~= >= <= <> and or like between || Символ ";" заменен на "END", чтобы можно было продолжать.
Вообще это дело вкуса, но лучше использовать SHOW ERRORS - так удобнее. И будет ясно видно где ошибка! Давайте удалим нашу "инвалидную" процедуру и вы сможете сами поработать над тем, что я вам излагал! Итак:
DROP PROCEDURE TESTERR / SQL> DROP PROCEDURE TESTERR 2 / Процедура удалена.
Пока все, поработайте сами! :)