Пакеты по умолчанию в PL/SQL: что нужно знать программисту?

Пакеты по умолчанию в PL/SQL: что нужно знать программисту?

В настоящем объектно-ориентированном языке — таком, как 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.

 

Вас заинтересует / Intresting for you:

Управление приложениями PL/SQL...
Управление приложениями PL/SQL... 4634 просмотров Stas Belkov Thu, 16 Jul 2020, 06:20:48
Встроенные методы коллекций PL...
Встроенные методы коллекций PL... 14738 просмотров sepia Tue, 29 Oct 2019, 09:54:01
Символьные функции и аргументы...
Символьные функции и аргументы... 18545 просмотров Анатолий Wed, 23 May 2018, 18:54:01
Тип данных RAW в PL/SQL
Тип данных RAW в PL/SQL 12239 просмотров Doctor Thu, 12 Jul 2018, 08:41:33
Войдите чтобы комментировать

OraCool аватар
OraCool ответил в теме #9478 4 года 5 мес. назад
Полезная статья. Автор, как всегда, на высоте!