Прежде чем переходить к описанию механизма выполнения программ PL/SQL
, необходимо определить пару важных понятий:
- Исполняющее ядро PL/SQL (виртуальная машина PL/SQL). Так называется компонент
Oracle
, выполняющий байт-код программPL/SQL
, который при необходимости вызывает сервер базы данных и возвращает результаты вызывающей среде. Исполняющее ядро написано на языке C. Традиционно оно включалось в некоторые клиентские инструменты, например Oracle Forms, где оно открывает сеанс подключения к удаленной базе данных и взаимодействует с ядромSQL
через сетевой протокол. - Сеанс (
Oracle
). Для большей части (серверного) кодаPL/SQL
сеансом называется процесс и пространство памяти, связанные с аутентифицированным пользователем. Каждый сеанс имеет собственную область памяти, в которой хранятся данные выполняемой программы. Сеансы начинаются с момента входа пользователя в систему и завершаются при выходе из нее. Для получения информации о текущих сеансах используется представлениеV$SESSI0N
.Oracle
поддерживает для сеанса различные виды памяти, включаяPGA
(Process Global Area),UGA
(User Global Area) иCGA
(Call Global Area); они будут рассматриваться далее в этом разделе.
Рассмотрим несколько способов выполнения простейшей программы из очень популярной клиентской среды SQL *Plus
. Это прекрасный пример приложения, ориентированного на выполнение в рамках сеанса и предоставляющего доступ к окружению PL/SQL
, которое входит в состав сервера базы данных. (Об SQL*Plus
и его использовании для выполнения кода PL/SQL
рассказывается в этом блоге.) Конечно, при желании к серверу можно обращаться с вызовами из других приложений (например, из клиентских программ Oracle
и даже из таких языков, как Perl
, C
или Java
). Происходящее на сервере практически не зависит от клиентского окружения.
При выполнении кода PL/SQL
из SQI?Plus
задействован анонимный блок верхнего уровня. Вы, вероятно, знаете, что команда EXECUTE
в SQL *Plus
преобразует вызов программы в анонимный блок, но известно ли вам, что команда SQL CALL
тоже генерирует упрощенную разновидность анонимного блока? По сути, прежде чем в Oracle9i
появилась возможность непосредственного вызова PL/SQL
из SQL
, все такого рода вызовы производились с использованием анонимных блоков.
Пример
Начнем с простейшего анонимного блока:
BEGIN
NULL;
END;
Что происходит при его отправке серверу Oracle
? Чтобы ответить на этот вопрос, обратимся к Рис. 1.
Проанализируем процесс, представленный на этом рисунке.
- Пользователь вводит исходный код блока, а затем отдает
SQLfPlus
команду на выполнение (косая черта). Как следует из рисунка,SQLfPlus
отправляет весь блок, за исключением косой черты, серверу. Передача осуществляется через соединение, установленное для текущего сеанса (например, черезOracle Net
или механизм межпроцессных коммуникаций).
Рис. 1. Выполнение тривиального анонимного блока
- Компилятор
PL/SQL
пытается откомпилировать полученный анонимный блок в байт-код. На первом этапе компилятор проверяет синтаксис и убеждается в том, что программа соответствует грамматике языка. В нашем тривиальном примере код не содержит ни одного идентификатора, а только ключевые слова языка. Если компиляция проходит успешно,Oracle
помещает байт-код блока в общую область памяти, а если нет — возвращает сообщения об ошибках сеансуSQLfPlus
. - Исполняющее ядро
PL/SQL
интерпретирует байт-код и возвращает сеансуSQLfPlus
признак успешного или неудачного завершения сеанса.
Добавим в анонимный блок SQL
-запрос и посмотрим, как изменится процесс его выполнения. На Рис. 2 показаны некоторые компоненты сервера Oracle
, участвующие в выполнении команд SQL
.
В этом примере значение столбца извлекается из встроенной таблицы DUAL
.
Убедившись в том, что код PL/SQL
не содержит синтаксических ошибок, компилятор PL/SQL
передает код SQL
компилятору SQL
. Аналогичным образом при вызове программ PL/SQL
из команд SQL
компилятор SQL
передает вызовы PL/SQL
компилятору PL/SQL
. Компилятор SQL
приводит выражения к непосредственно исполняемому виду, анализирует возможности применения кэшированных результатов функций (начиная с Oraclellg), проверяет семантику и синтаксис, проводит разрешение имен и определяет оптимальный план выполнения. Все эти действия являются частью фазы разбора SQL
-выражения и предшествуют подстановкам связанных переменных, выполнению и выборке команд SQL.
Хотя PL/SQL
использует компилятор SQL
совместно с базой данных, это не означает, что в PL/SQL
доступны все функции SQL
. Например, SQL
поддерживает функцию NVL2
:
SELECT NVL2(NULL, 1, 2) FROM DUAL;
Однако попытка вызова NVL2
непосредственно из PL/SQL
приводит к ошибке (PLS- 00201
):
SQL> EXEC DBMS_OUTPUT.PUT_LINE(NVL2(NULL, 1, 2));
2 BEGIN DBMS_OUTPUT.PUT_LINE (NVL2(NULL, 1, 2)); END;
*
ERROR at line 1:
ORA-06550: line 1, column 28:
PLS-00201: identifier 'NVL2' must be declared
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
Рис. 2. Выполнение анонимного блока, содержащего команду SQL
При компиляции программы PL/SQL
встроенные команды SQL
подвергаются незначительным преобразованиям: из них удаляются секции INTO
, на место локальных переменных программы подставляются связанные значения, удаляются комментарии, а многие идентификаторы (ключевые слова, имена столбцов, имена таблиц и т. д., но не рекомендации и литералы) преобразуются в верхний регистр. Например, если myvar
является локальной переменной, PL/SQL
преобразует команду select dummy into str from dual where dummy = myvar
к следующему виду:
select dummy into str from dual where dummy = myvar
к следующему виду:
SELECT DUMMY FROM DUAL WHERE DUMMY = :B1
Из кода PL/SQL
могут совершаться внешние вызовы двух типов:
- Хранимые процедуры Java. Стандартная установка сервера баз данных включает не только виртуальную машину
PL/SQL
, но и виртуальную машинуJava
. Вы можете написать спецификацию вызоваPL/SQL
, логика которого реализуется в виде статического классаJava
. - Внешние процедуры. Исполняемую часть подпрограммы
PL/SQL
также можно реализовать в коде C. Во время работы база данных будет выполнять код в особом процессе и пространстве памяти, отделенных от главного сервера базы данных. Вы отвечаете за поддержку двоичных файлов и наличие копии у каждого узлаRAS
.
Ограничения компилятора
При компиляции очень большой программы PL/SQL
от сервера можно получить сообщение об ошибке PLS-00123
. Это означает, что компилятор вышел за пределы максимально допустимого количества узлов в дереве разбора. В таком случае программу проще всего разбить на несколько меньших подпрограмм или изменить ее архитектуру (например, использовать временную таблицу вместо 10 000 параметров). Трудно предсказать, сколько узлов понадобится для реализации программы, потому что не каждый узел соответствует какой-либо легко идентифицируемой единице исходного кода (лексеме, строке кода и т. д.).
По данным Oracle
, «типичная» хранимая программа создает в среднем четыре узла на каждую строку кода, что дает следующие приблизительные ограничения:
Тип программы PL/SQL | Приблизительный максимальный размер исходного кода в байтах |
Тело пакета или типа; автономные функции и процедуры | 256 Мбайт |
Сигнатура (заголовок) отдельной функции или процедуры | 128 Kбайт |
Спецификация пакета или типа данных, анонимный блок | 128 Kбайт |
Приведенные значения весьма приблизительны; в реальных программах возможны значительные отклонения в обоих направлениях.
Некоторые из других документированных ограничений компилятора PL/SQL
перечислены в следующей таблице.
Тип программы PL/SQL | Максимальное значение (приблизительное) |
Уровни вложения блоков | 255 |
Параметры, передаваемые процедуре или функции | 65 536 |
Уровни вложения записей | 64 |
Ссылки на объекты в программах | 65 536 |
Количество обработчиков исключений в одной программе | 65 536 |
Точность NUMBER (в знаках) | 38 |
Размер VARCHAR2 (в байтах) | 32 767 |