В настоящем объектно-ориентированном языке — таком, как Java
, — имеется корневой класс, производными от которого являются все остальные классы. (В Java
он называется Object
.) PL/SQL официально считается объектно-реляционным языком, но по своей сути он является реляционным процедурным языком, а в самой его основе лежит «корневой» пакет с именем STANDARD
.
Пакеты PL/SQL, которые вы создаете, не являются производными от STANDARD
, но почти каждая написанная вами программа будет зависеть от этого пакета и использовать его. Собственно, это один из двух используемых по умолчанию пакетов PL/SQL (второй — dbms_standard
).
Чтобы лучше понять роль этих пакетов в среде программирования, стоит вернуться к концу 1980-х годов, когда еще не было ни Oracle7
, ни SQL*Forms 3
, не было даже Oracle PL/SQL
. Тогда выяснилось, что SQL
— замечательный язык, но его возможности ограничены. Клиенты Oracle
писали программы C, выполнявшие команды SQL
, но эти программы приходилось изменять для каждой новой операционной системы.
Было решено создать язык программирования, который мог бы выполнять команды SQL
и при этом работать во всех операционных системах, в которых установлена база данных Oracle
. Также компания Oracle
решила, что вместо изобретения собственного языка она проанализирует существующие языки и определит, не могут ли они стать прототипом для того, чем в будущем стал PL/SQL
.
В итоге за прототип был взят язык Ada
, изначально разработанный для Министерства обороны США. Конструкция пакетов была позаимствована из Ada
. В этом языке можно задать «пакет по умолчанию» для любой программной единицы. Имена элементов пакета по умолчанию не нужно уточнять именем пакета (как в конструкциях вида мой_пакет. процедура).
При проектировании PL/SQL
идея пакета по умолчанию была сохранена, но способ ее применения несколько изменился. Пользователи PL/SQL
не могут задать пакет по умолчанию для программной единицы. В PL/SQL
существует два пакета по умолчанию, STANDARD
и DBMS_STANDARD
. Они используются по умолчанию во всем языке, а не в конкретной программной единице.
Имена элементов этих пакетов почти всегда используются без уточнения имен. Пакет STANDARD
объявляет набор типов, исключений и подпрограмм, автоматически доступных в любой программе PL/SQL
; многие программисты PL/SQL
(ошибочно) считают их «зарезервированными словами» языка. При компиляции кода компилятор Oracle
должен разрешить все идентификаторы без уточнения имен; сначала Oracle
проверяет, объявлен ли элемент с таким именем в текущей области видимости. Если нет, Oracle проверяет, определен ли элемент с таким именем в пакете STANDARD
или DBMS_STANDARD
. Если все идентификаторы будут найдены успешно (и в коде не обнаружены синтаксические ошибки), то код компилируется.
Чтобы понять роль пакета STANDARD
, рассмотрим следующий, очень странный блок кода PL/SQL
. Как вы думаете, что произойдет при выполнении этого блока?
1 DECLARE
2 SUBTYPE DATE IS NUMBER;
3 VARCHAR2 DATE := 11111;
4 TO_CHAR PLS_INTEGER;
5 NO_DATA_FOUND EXCEPTION;
6 BEGIN
7 SELECT 1 INTO TO_CHAR
8 FROM SYS.DUAL WHERE 1 = 2;
9 EXCEPTION
10 WHEN NO_DATA_FOUND
11 THEN
12 DBMS_OUTPUT.put_line ('Trapped!');
13 END;
Большинство разработчиков PL/SQL
скажет: «Этот блок не откомпилируется» или «Будет выведено сообщение «Trapped
!», потому что 1 не равно 2».
В действительности блок откомпилируется, но при его выполнении произойдет необработанное исключение NO_DATA_FOUND
:
ORA-01403: no data found
ORA-06512: at line 7
Странно, не правда ли? NO_DATA_FOUND
, единственное исключение, которое обрабатывается в программе, — как оно осталось необработанным? Вопрос в том, какое исключение NO_DATA_FOUND
обрабатывается в программе? В этом блоке мы объявляем собственное исключение с именем NO_DATA_FOUND
. Это имя не является зарезервированным словом языка PL/SQL
(в отличие, скажем, от BEGIN
— объявить переменную с именем BEGIN
невозможно). В спецификации пакета STANDARD
одноименное исключение определяется следующим образом:
NO_DATA_FOUND exception;
PRAGMA EXCEPTION_INIT(NO_DATA_FOUND, 100);
Так как в нашем блоке имеется локально объявленное исключение с именем NO_DATA_ FOUND
, любые неуточненные ссылки на этот идентификатор в блоке считаются относящимися именно к нему, а не к исключению пакета STANDARD
. Если команда SELECT INTO
не находит ни одной строки, инициируется исключение STANDARD.NO_DATA_FOUND
— а это совсем не то исключение, которое обрабатывается в разделе исключений.
С другой стороны, если привести строку 12 в разделе исключений к следующему виду:
WHEN STANDARD.NO_DATA_FOUND
то исключение будет успешно обработано, а программа выведет слово «Trapped
!».
Кроме неоднозначной ситуации с NO_DATA_FOUND
, следующие строки тоже выглядят довольно странно.
Строки | Описание |
2 | Определение нового типа данных «DATE », который на самом деле относится к типу NUMBER |
3 | Объявление переменной «VARCHAR2 » типа DATA и присваивание ей значения 11111 |
4 | Объявление переменной «TO_CHAR » типа PLS_INTEGER |
Мы можем «использовать заново» эти имена «встроенных» элементов языка PL/ SQL
, потому что все они определяются в пакете STANDARD
. Эти имена не являются зарезервированными словами PL/SQL
; их просто и удобно использовать без указания имени пакета.
Пакет STANDARD
содержит определения типов данных, поддерживаемых в PL/SQL
, заранее определенных исключений и встроенных функций (TO_CHAR
, SYSDATE
, USER
и т. д.). Пакет DBMS_STANDARD
содержит элементы, относящиеся к работе с транзакциями (такие, как commit
и rollback
), а также функции триггерных событий inserting
, deleting
и updating
. Несколько замечаний по поводу STANDARD
:
- Никогда не изменяйте содержимое этого пакета. А если вы это сделаете, не обращайтесь в службу поддержки
Oracle
за помощью — ведь вы нарушили соглашение о сопровождении продукта! Чтобы вы могли изучить содержимое этого пакета и других пакетов (таких, какdbms_output
— см.dbmsotpt.sql
) иdbms_utility
(см.dbmsutil.sql
), администратор базы данных должен предоставить вам доступ только для чтения для каталогаRDBMS/Admin
. Oracle
даже позволяет прочитать тело пакетаSTANDARD
; тела большинства пакетов (например,DBMS_SQL
) скрываются или защищаются псевдошифрованием. Загляните в сценарийstdbody.sql
; вы увидите, например, что функцияUSER
всегда выполняетSELECT
изSYS.dual
, аSYSDATE
выполняет запрос только в том случае, если при выполнении программы C для получения системной временной метки происходит ошибка.- Присутствие некоторой конструкции в
STANDARD
еще не означает, что вы можете использовать точно такой же код в своих блокахPL/SQL
. Например, вам не удастся объявить подтип с диапазоном значений, как это делается дляBINARY_INTEGER
. - Если некоторый элемент определяется в
STANDARD
, это еще не означает, что его можно использовать вPL/SQL
. Например, функцияDECODE
объявлена вSTANDARD
, но вызывать ее можно только из командSQL
.
Пакет STANDARD
определяется в файлах stdspec.sql
и stdbody.sql
из каталога $ORACLE_HOME/ RDBMS/Admin
(в ранних версиях базы данных этот пакет находился в файле standard.sql
). Пакет DBMS_STANDARD
определяется в файле dbmsstdx.sql
.
Если вам интересно, какие из многочисленных предопределенных идентификаторов являются зарезервированными словами в языке PL/SQL
, воспользуйтесь сценарием reserved_words.sql
.
Кроме рассмотренной темы, программист PL/SQL должен очень хорошо представлять модели предоставления доступа в СУБД Oracle.