Ограничение NOT NULL
Для локальных переменных можно указать ограничение NOT NULL
, тем самым запретив передавать в него значение NULL
.
NOT NULL
Для локальных переменных можно указать ограничение NOT NULL
, тем самым запретив передавать в него значение NULL
.
CHARACTER SET
и COLLATE
Если не указано иное, набор символов и последовательность сопоставления (сортировки) строковой переменной будут значениями по умолчанию для базы данных.
При необходимости можно включить предложение CHARACTER SET
для обработки строковых данных, которые будут находиться в другом наборе символов.
Допустимая последовательность сопоставления (предложение COLLATE
) также может быть включена с CHARACTER SET
или без него.
Локальной переменной можно устанавливать инициализирующее (начальное) значение.Это значение устанавливается с помощью предложения DEFAULT
или оператора “=”.В качестве значения по умолчанию может быть использовано значение NULL
,литерал и любая контекстная переменная совместимая по типу данных.
Important
|
Обязательно используйте инициализацию начальным значением для любых переменных объявленных с ограничением |
CREATE OR ALTER PROCEDURE SOME_PROC
AS
-- Объявление переменной типа INT
DECLARE I INT;
-- Объявление переменной типа INT не допускающей значение NULL
DECLARE VARIABLE J INT NOT NULL;
-- Объявление переменной типа INT со значением по умолчанию 0
DECLARE VARIABLE K INT DEFAULT 0;
-- Объявление переменной типа INT со значением по умолчанию 1
DECLARE VARIABLE L INT = 1;
-- Объявление переменной на основе домена COUNTRYNAME
DECLARE FARM_COUNTRY COUNTRYNAME;
-- Объявление переменной с типом равным типу домена COUNTRYNAME
DECLARE FROM_COUNTRY TYPE OF COUNTRYNAME;
-- Объявление переменной с типом столбца CAPITAL таблицы COUNTRY
DECLARE CAPITAL TYPE OF COLUMN COUNTRY.CAPITAL;
BEGIN
/* Операторы PSQL */
END
IN AUTONOMOUS TRANSACTION
Выполнение составного оператора в автономной транзакции.
PSQL.
IN AUTONOMOUS TRANSACTION DO <compound_statement>
Параметр | Описание |
---|---|
compound_statement |
Составной оператор (оператор или блок операторов). |
Оператор IN AUTONOMOUS TRANSACTION
позволяет выполнить составной оператор в автономной транзакции.Код, работающий в автономной транзакции, будет подтверждаться сразу же после успешного завершения независимо от состояния родительской транзакции.Это бывает нужно, когда определённые действия не должны быть отменены, даже в случае возникновения ошибки в родительской транзакции.
Автономная транзакция имеет тот же уровень изоляции, что и родительская транзакция.Любое исключение, вызванное или появившееся в блоке кода автономной транзакции, приведёт к откату автономной транзакции и отмене всех внесённых изменений.Если код будет выполнен успешно, то автономная транзакция будет подтверждена.
IN AUTONOMOUS TRANSACTION
Данный пример демонстрирует использование автономной транзакции в триггере на событие подключения к базеданных для регистрации всех попыток соединения, в том числе и неудачных.
CREATE TRIGGER TR_CONNECT ON CONNECT
AS
BEGIN
-- Все попытки соединения с БД сохраняем в журнал
IN AUTONOMOUS TRANSACTION DO
INSERT INTO LOG(MSG)
VALUES ('USER ' || CURRENT_USER || ' CONNECTS.');
IF (CURRENT_USER IN (SELECT
USERNAME
FROM
BLOCKED_USERS)) THEN
BEGIN
-- Сохраняем в журнал, что попытка соединения
-- с БД оказалась неудачной
-- и отправляем сообщение о событии
IN AUTONOMOUS TRANSACTION DO
BEGIN
INSERT INTO LOG(MSG)
VALUES ('USER ' || CURRENT_USER || ' REFUSED.');
POST_EVENT 'CONNECTION ATTEMPT' || ' BY BLOCKED USER!';
END
-- теперь вызываем исключение
EXCEPTION EX_BADUSER;
END
END
POST_EVENT
Посылка события (сообщения) клиентским приложениям.
PSQL
POST_EVENT event_name;
Параметр | Описание |
---|---|
event_name |
Имя события, ограничено 127 байтами. |
Оператор POST_EVENT
сообщает о событии менеджеру событий, который сохраняет его в таблице событий.При подтверждении транзакции менеджер событий информирует приложения, ожидающие это событие.
Имя события это своего рода код или короткое сообщение, выбор за вами, т.к.это просто строка длинной до 127 байт.
В качестве имени события может быть использован строковый литерал, переменная или любое правильное SQL выражение.
POST_EVENT
SALES
SET TERM ^;
CREATE TRIGGER POST_NEW_ORDER FOR SALES
ACTIVE AFTER INSERT POSITION 0
AS
BEGIN
POST_EVENT 'new_order';
END^
SET TERM ;^
RETURN
Возврат значения из хранимой функции
PSQL
RETURN value;
Параметр | Описание |
---|---|
value |
Выражение для возврата значения из функции;Может быть любым выражением, совместимым с типом возвращаемого значения функции. |
Оператор RETURN
завершает выполнение функции и возвращает значение выражения value.
RETURN
может использоваться только в PSQL функциях (хранимых и локальных функциях).
RETURN
В Firebird существуют PSQL операторы для обработки ошибок и исключений в модулях.Существует множество встроенных исключений, которые возникают в случае возникновения стандартных ошибок при работе с DML и DDL операторами.
Исключение представляет собой сообщение, которое генерируется, когда возникает ошибка.
Все обрабатываемые Firebird исключения имеют заранее определённые числовые (символьные) значение для контекстных переменных и связанные с ними тексты сообщений.Сообщения об ошибке написаны по умолчанию на английском языке.Существуют и локализованные сборки СУБД, в которых сообщения об ошибках переведены на другие языки.
Полный список системных исключений вы можете найти в приложении "Обработка ошибок, коды и сообщения":
Пользовательские исключения могут быть объявлены в базе данных как постоянные объекты и вызваны из PSQL кода для сообщения об ошибке при нарушении некоторых бизнес правил.Текст пользовательского исключения ограничен 1021 байтом.Подробности см. CREATE EXCEPTION.
В коде PSQL исключения обрабатываются при помощи оператора WHEN
.Если исключение будет обработано в вашем коде, то вы обеспечите исправление или обход ошибки и позволите продолжить выполнение, то клиенту не возвращается никакого сообщения об исключении.
Исключение приводит к прекращению выполнения в блоке.Вместо того чтобы передать выполнение на конечный оператор END
, теперь процедура отыскивает уровни во вложенных блоках, начиная с блока где была вызвана ошибка, и переходит на внешние блоки, чтобы найти код обработчика, который “знает” о таком исключении.Она отыскивает первый оператор WHEN
, который может обработать эту ошибку.
EXCEPTION
Возбуждение пользовательского исключения или повторный вызов исключения.
PSQL
EXCEPTION [ exception_name [ custom_message | USING (<value_list>)] ] <value_list> ::= <val> [, <val> ...]
Параметр | Описание |
---|---|
exception_name |
Имя исключения. |
custom_message |
Альтернативный текст сообщения, выдаваемый при возникновении исключения.Максимальная длина текстового сообщения составляет 1021 байт. |
val |
Значения, которыми заменяются слоты в тексте сообщения исключения. |
Оператор EXCEPTION
возбуждает пользовательское исключение с указанным именем.При возбуждении исключения можно также указать альтернативный текст сообщения, который заменит текст сообщения заданным при создании исключения.
Текст сообщения исключения может содержать слоты для параметров, которые заполняются при возбуждении исключения.Для передачи значений параметров в исключение используется предложение USING
.Параметры рассматриваются слева направо.Каждый параметр передаётся в оператор возбуждающий исключение как “N-ый”, N начинается с 1:
Если N-ый параметр не передан, его слот не заменяется;
Если передано значение NULL
, слот будет заменён на строку “*** null ***
”;
Если количество передаваемых параметров будет больше, чем содержится в сообщении исключения, то лишние будут проигнорированы;
Максимальный номер параметра равен 9;
Общая длина сообщения, включая значения параметров, ограничена 1053 байтами.
Note
|
Статус вектор генерируется, используя комбинацию кодов Поскольку используется новый код ошибки ( |
Warning
|
Если в тексте сообщения, встретится номер слота параметра больше 9, то второй и последующий символ будут восприняты как литералы.Например, |
CREATE EXCEPTION ex1
'something wrong in @1 @2 @3 @4 @5 @6 @7 @8 @9 @10 @11';
EXECUTE BLOCK AS
BEGIN
EXCEPTION ex1 USING ('a','b','c','d','e','f','g','h','i');
END^
Statement failed, SQLSTATE = HY000 exception 1 -EX1 -something wrong in a b c d e f g h i a0 a1
Исключение может быть обработано в операторе WHEN … DO.Если пользовательское исключение не было обработано в триггере или в хранимой процедуре, то действия, выполненные внутри этой хранимой процедуры (триггера) отменяются, а вызвавшая программа получает текст, заданный при создании исключения или альтернативный текст сообщения.
В блоке обработки исключений (и только в нем), вы можете повторно вызвать пойманное исключение или ошибку, вызывая оператор EXCEPTION без параметров.Вне блока с исключением такой вызов не имеет никакого эффекта.
Note
|
Пользовательские исключения хранятся в системной таблице |
EXCEPTION
CREATE OR ALTER PROCEDURE SHIP_ORDER (
PO_NUM CHAR(8))
AS
DECLARE VARIABLE ord_stat CHAR(7);
DECLARE VARIABLE hold_stat CHAR(1);
DECLARE VARIABLE cust_no INTEGER;
DECLARE VARIABLE any_po CHAR(8);
BEGIN
SELECT
s.order_status,
c.on_hold,
c.cust_no
FROM
sales s, customer c
WHERE
po_number = :po_num AND
s.cust_no = c.cust_no
INTO :ord_stat,
:hold_stat,
:cust_no;
/* Этот заказ уже отправлен на поставку. */
IF (ord_stat = 'shipped') THEN
EXCEPTION order_already_shipped;
/* Другие операторы */
END
CREATE OR ALTER PROCEDURE SHIP_ORDER (
PO_NUM CHAR(8))
AS
DECLARE VARIABLE ord_stat CHAR(7);
DECLARE VARIABLE hold_stat CHAR(1);
DECLARE VARIABLE cust_no INTEGER;
DECLARE VARIABLE any_po CHAR(8);
BEGIN
SELECT
s.order_status,
c.on_hold,
c.cust_no
FROM
sales s, customer c
WHERE
po_number = :po_num AND
s.cust_no = c.cust_no
INTO :ord_stat,
:hold_stat,
:cust_no;
/* Этот заказ уже отправлен на поставку. */
IF (ord_stat = 'shipped') THEN
EXCEPTION order_already_shipped 'Order status is "' || ord_stat || '"';
/* Другие операторы */
END
CREATE EXCEPTION EX_BAD_SP_NAME
'Name of procedures must start with ''@1'' : ''@2''';
...
CREATE TRIGGER TRG_SP_CREATE BEFORE CREATE PROCEDURE
AS
DECLARE SP_NAME VARCHAR(255);
BEGIN
SP_NAME = RDB$GET_CONTEXT('DDL_TRIGGER', 'OBJECT_NAME');
IF (SP_NAME NOT STARTING 'SP_') THEN
EXCEPTION EX_BAD_SP_NAME USING ('SP_', SP_NAME);
END^
WHEN … DO
Обработка ошибок.
PSQL
WHEN {<error> [, <error> ...] | ANY} DO <compound_statement> <error> ::= { EXCEPTION exception_name | SQLCODE number | GDSCODE errcode | SQLSTATE 'sqlstate_code' }
Параметр | Описание |
---|---|
exception_name |
Имя исключения. |
number |
Код ошибки SQLCODE. |
errcode |
Символическое имя ошибки GDSCODE. |
sqlstate_code |
Код ошибки SQLSTATE. |
compound_statement |
Оператор или блок операторов. |
Оператор WHEN … DO
используется для обработки ошибочных ситуаций и пользовательских исключений.Оператор перехватывает все ошибки и пользовательские исключения, перечисленные после ключевого слова WHEN
.Если после ключевого слова WHEN
указано ключевое слово ANY
, то оператор перехватывает любые ошибки и пользовательские исключения, даже если они уже были обработаны в вышестоящем WHEN
блоке.
Оператор WHEN … DO
должен находиться в самом конце блока операторов перед оператором END
.
После ключевого слова DO
следует составной оператор, в котором можно произвести обработку ошибки или исключения.Составной оператор — это оператор или блок операторов, заключённый в операторные скобки BEGIN
и END
.В этом операторе доступны контекстные переменные GDSCODE, SQLCODE, SQLSTATE.Для получения имени активного пользовательского исключения или текста интерпретированного сообщения об ошибке вы можете воспользоваться системной функцией RDB$ERROR.В этом же блоке доступен оператор повторного вызова ошибки или исключительной ситуации EXCEPTION
(без параметров).
Important
|
После предложения |
Оператор WHEN … DO
вызывается только в том случае, если произошло одно из указанных в его условии событий.В случае выполнения оператора (даже если в нем фактически не было выполнено никаких действий) ошибка или пользовательское исключение не прерывает и не отменяет действий триггера или хранимой процедуры, где был выдан этот оператор, работа продолжается, как если бы никаких исключительных ситуаций не было.Однако в этом случае будет отменено действие DML оператора (SELECT
, INSERT
, UPDATE
, DELETE
, MERGE
), который вызвал ошибку и все ниже находящиеся операторы в том же блоке операторов не будут выполнены.
Important
|
Если ошибка вызвана не одним из DML операторов ( |
WHEN … DO
Оператор перехватывает ошибки и исключения в текущем блоке операторов.Он также перехватывает подобные ситуации во вложенных блоках, если эти ситуации не были в них обработаны.
Оператор WHEN … DO
видит все изменения, произведённые до оператора вызвавшего ошибку.Однако если вы попытаетесь запротоколировать их в автономной транзакции, то эти изменения будут не доступны, поскольку на момент старта автономной транзакции, транзакция, в которой произошли эти изменения, не подтверждена.
WHEN…DO
CREATE EXCEPTION COUNTRY_EXIST '';
SET TERM ^;
CREATE PROCEDURE ADD_COUNTRY (
ACountryName COUNTRYNAME,
ACurrency VARCHAR(10) )
AS
BEGIN
INSERT INTO country (country, currency)
VALUES (:ACountryName, :ACurrency);
WHEN SQLCODE -803 DO
EXCEPTION COUNTRY_EXIST 'Такая страна уже добавлена!';
END^
SET TERM ^;
WHEN
.CREATE PROCEDURE ADD_COUNTRY (
ACountryName COUNTRYNAME,
ACurrency VARCHAR(10) )
AS
BEGIN
INSERT INTO country (country,
currency)
VALUES (:ACountryName,
:ACurrency);
WHEN ANY DO
BEGIN
-- Записываем ошибку в журнал
IN AUTONOMOUS TRANSACTION DO
INSERT INTO ERROR_LOG (PSQL_MODULE,
ERROR_TEXT,
EXCEPTION_NAME,
GDS_CODE,
SQL_CODE,
SQL_STATE)
VALUES ('ADD_COUNTRY',
RDB$ERROR(MESSAGE), -- текст сообщения об ошибке
RDB$ERROR(EXCEPTION), -- имя пользовательского исключения
GDSCODE,
SQLCODE,
SQLSTATE
);
-- Повторно возбуждаем ошибку
EXCEPTION;
END
END
WHEN … DO
блоке нескольких ошибок...
WHEN GDSCODE GRANT_OBJ_NOTFOUND,
GDSCODE GRANT_FLD_NOTFOUND,
GDSCODE GRANT_NOPRIV,
GDSCODE GRANT_NOPRIV_ON_BASE
DO
BEGIN
EXECUTE PROCEDURE LOG_GRANT_ERROR(GDSCODE);
EXIT;
END
...
SQLSTATE
.EXECUTE BLOCK
AS
DECLARE VARIABLE I INT;
BEGIN
BEGIN
I = 1 / 0;
WHEN SQLSTATE '22003' DO
EXCEPTION E_CUSTOM_EXCEPTION
'Numeric value out of range.';
WHEN SQLSTATE '22012' DO
EXCEPTION E_CUSTOM_EXCEPTION 'Division by zero.';
WHEN SQLSTATE '23000' DO
EXCEPTION E_CUSTOM_EXCEPTION
'Integrity constraint violation.';
END
END
DECLARE … CURSOR
Объявление курсора.
PSQL
DECLARE [VARIABLE] cursor_name [SCROLL | NO SCROLL] CURSOR FOR (<select_statement>);
Параметр | Описание |
---|---|
cursor_name |
Имя курсора. |
select_statement |
Оператор SELECT. |
Оператор DECLARE … CURSOR FOR
объявляет именованный курсор, связывая его с набором данных, полученным в операторе SELECT
, указанном в предложении CURSOR FOR
.В дальнейшем курсор может быть открыт, использоваться для обхода результирующего набора данных, и снова быть закрытым.Также поддерживаются позиционированные обновления и удаления при использовании WHERE CURRENT OF
в операторах UPDATE
и DELETE
.
Имя курсора можно использовать в качестве ссылки на курсор, как на переменные типа запись.Текущая запись доступна через имя курсора, что делает необязательным предложение INTO
в операторе FETCH
.
Курсор может быть однонаправленными прокручиваемым.Необязательное предложение SCROLL
делает курсор двунаправленным (прокручиваемым), предложение NO SCROLL
— однонаправленным.По умолчанию курсоры являются однонаправленными.
Однонаправленные курсоры позволяют двигаться по набору данных только вперёд.Двунаправленные курсоры позволяют двигаться по набору данных не только вперёд, но и назад, а также на N позиций относительно текущего положения.
Warning
|
Прокручиваемые курсоры материализуются внутри как временный набор данных, таким образом, они потребляют дополнительные ресурсы памяти/диска, поэтому пользуйтесь ими только тогда, когда это действительно необходимо. |
Предложение FOR UPDATE
разрешено использовать в операторе SELECT
, но оно не требуется для успешного выполнения позиционированного обновления или удаления;
Удостоверьтесь, что объявленные имена курсоров не совпадают, ни с какими именами, определёнными позже в предложениях AS CURSOR
;
Если курсор требуется только для прохода по результирующему набору данных, то практически всегда проще (и менее подвержено ошибкам) использовать оператор FOR SELECT
с предложением AS CURSOR
. Объявленные курсоры должны быть явно открыты, использованы для выборки данных и закрыты. Кроме того, вы должны проверить контекстную переменную ROW_COUNT
после каждой выборки и выйти из цикла, если её значение ноль. Предложение FOR SELECT
делает эту проверку автоматически. Однако объявленные курсоры дают большие возможности для контроля над последовательными событиями и позволяют управлять несколькими курсорами параллельно;
Оператор SELECT
может содержать параметры, например: "SELECT NAME || :SFX FROM NAMES WHERE NUMBER = :NUM". Каждый параметр должен быть заранее объявлен как переменная PSQL (это касается также входных и выходных параметров). При открытии курсора параметру присваивается текущее значение переменной;
Если опция прокрутки опущена, то по умолчанию принимается NO SCROLL (т.е курсор открыт для движения только вперёд). Это означает, что могут быть использованы только команды FETCH [NEXT FROM]
. Другие команды будут возвращать ошибки.
Warning
|
Если значение переменной PSQL, используемой в операторе |
CREATE OR ALTER TRIGGER TBU_STOCK
BEFORE UPDATE ON STOCK
AS
-- Объявление именованного курсора
DECLARE C_COUNTRY CURSOR FOR (
SELECT
COUNTRY,
CAPITAL
FROM COUNTRY
);
BEGIN
/* Операторы PSQL */
END
EXECUTE BLOCK
RETURNS (
N INT,
RNAME CHAR(63))
AS
-- Объявление прокручиваемого курсора
DECLARE C SCROLL CURSOR FOR (
SELECT
ROW_NUMBER() OVER(ORDER BY RDB$RELATION_NAME) AS N,
RDB$RELATION_NAME
FROM RDB$RELATIONS
ORDER BY RDB$RELATION_NAME);
BEGIN
/* Операторы PSQL */
END
DECLARE PROCEDURE
Объявление и реализация подпроцедуры.
PSQL
<subproc-declaration> ::= DECLARE PROCEDURE subprocname [(<input-parameters>)] [RETURNS (<output-parameters>)]; <subproc-implimentation> ::= DECLARE PROCEDURE subprocname [(<input-parameters>)] [RETURNS (<output-parameters>)] <psql-routine-body> <input-parameters> ::= <inparam> [, <inparam> ...] <output-parameters> ::= <outparam> [, <outparam> ...] <psql-routine-body> ::= См. Синтаксис тела модуля
Параметр | Описание |
---|---|
subprocname |
Имя подпроцедуры. |
inparam |
Описание входного параметра. |
outparam |
Описание выходного параметра. |
Оператор DECLARE PROCEDURE
объявляет или реализует подпроцедуру.
На подпроцедуру накладываются следующие ограничения:
Подпрограмма не может быть вложена в другую подпрограмму. Они поддерживаются только в основном модуле (хранимой процедуре, хранимой функции, триггере и анонимном PSQL блоке);
Переменные из основного модуля доступны внутри подпрограммы;
При чтении переменные и параметры, к которым обращаются подпрограммы, могут иметь небольшое снижение производительности (даже в основной программе).
В настоящее время подпрограмма не имеет прямого доступа до курсоров из основного модуля. Это может быть разрешено в будущем.
Одна подпрограмма может вызывать и другую подпрограмму, в том числе рекурсивно.В ряде случаев может потребоваться предварительное объявление подпрограммы.Общее правило: одна подпрограмма может вызвать другую подпрограмму, если последняя объявлена выше точки вызова.Все объявленные подпрограммы должны быть реализованы с той же сигнатурой.Значения по умолчанию для параметров подпрограмм не могут быть переопределены.Это означает, что они могут быть определены в реализации только тех подпрограмм, которые не были объявлены ранее.
SET TERM ^;
--
-- Подпроцедуры в EXECUTE BLOCK
--
EXECUTE BLOCK
RETURNS (
name VARCHAR(63))
AS
-- Подпроцедура, возвращающая список таблиц
DECLARE PROCEDURE get_tables
RETURNS(table_name VARCHAR(63))
AS
BEGIN
FOR
SELECT
rdb$relation_name
FROM
rdb$relations
WHERE
rdb$view_blr IS NULL
INTO table_name
DO SUSPEND;
END
-- Подпроцедура, возвращающая список представлений
DECLARE PROCEDURE get_views
RETURNS(view_name VARCHAR(63))
AS
BEGIN
FOR
SELECT
rdb$relation_name
FROM
rdb$relations
WHERE
rdb$view_blr IS NOT NULL
INTO view_name
DO SUSPEND;
END
BEGIN
FOR
SELECT
table_name
FROM
get_tables
UNION ALL
SELECT
view_name
FROM
get_views
INTO name
DO SUSPEND;
END^
EXECUTE BLOCK RETURNS (o INTEGER)
AS
-- Предварительное объявление P1.
DECLARE PROCEDURE p1(i INTEGER = 1) RETURNS (o INTEGER);
-- Предварительное объявление P2.
DECLARE PROCEDURE p2(i INTEGER) RETURNS (o INTEGER);
-- Реализация P1. Вы не должны переопределять значение параметра по умолчанию
DECLARE PROCEDURE p1(i INTEGER) RETURNS (o INTEGER)
AS
BEGIN
EXECUTE PROCEDURE p2(i) RETURNING_VALUES o;
END
DECLARE PROCEDURE p2(i INTEGER) RETURNS (o INTEGER)
AS
BEGIN
o = i;
END
BEGIN
EXECUTE PROCEDURE p1 RETURNING_VALUES o;
SUSPEND;
END!
Объявление и реализация подфункции.
PSQL
<subfunc-declaration> ::= DECLARE FUNCTION subfuncname [(<input-parameters>)] RETURNS <type> [COLLATE collation] [DETERMINISTIC]; <subfunc-implimentation> ::= DECLARE FUNCTION subfuncname [(<input-parameters>)] RETURNS <type> [COLLATE collation] [DETERMINISTIC] <psql-routine-body> <input-parameters> ::= <inparam> [, <inparam> ...] <output-parameters> ::= <outparam> [, <outparam> ...] <psql-routine-body> ::= См. Синтаксис тела модуля
Параметр | Описание |
---|---|
subfuncname |
Имя подфункции. |
inparam |
Описание входного параметра. |
type |
Тип выходного результата. |
collation |
Порядок сортировки. |
Оператор DECLARE FUNCTION
объявляет подфункцию.
На подфункцию накладываются следующие ограничения:
Подпрограмма не может быть вложена в другую подпрограмму. Они поддерживаются только в основном модуле (хранимой процедуре, хранимой функции, триггере и анонимном PSQL блоке);
Переменные из основного модуля доступны внутри подпрограммы;
При чтении переменные и параметры, к которым обращаются подпрограммы, могут иметь небольшое снижение производительности (даже в основной программе).
В настоящее время подпрограмма не имеет прямого доступа до курсоров из основного модуля. Это может быть разрешено в будущем.
Одна подпрограмма может вызывать и другую подпрограмму, в том числе рекурсивно.В ряде случаев может потребоваться предварительное объявление подпрограммы.Общее правило: одна подпрограмма может вызвать другую подпрограмму, если последняя объявлена выше точки вызова.Все объявленные подпрограммы должны быть реализованы с той же сигнатурой.Значения по умолчанию для параметров подпрограмм не могут быть переопределены.Это означает, что они могут быть определены в реализации только тех подпрограмм, которые не были объявлены ранее.
--
-- Подфункция внутри хранимой функции
--
CREATE OR ALTER FUNCTION FUNC1 (n1 INTEGER, n2 INTEGER)
RETURNS INTEGER
AS
-- Подфункция
DECLARE FUNCTION SUBFUNC (n1 INTEGER, n2 INTEGER)
RETURNS INTEGER
AS
BEGIN
RETURN n1 + n2;
END
BEGIN
RETURN SUBFUNC(n1, n2);
END ^
EXECUTE BLOCK RETURNS (i INTEGER, o INTEGER)
AS
-- Рекусривная подпрограмма-функция без предварительного объявления.
DECLARE FUNCTION fibonacci(n INTEGER) RETURNS INTEGER
AS
BEGIN
IF (n = 0 OR n = 1) THEN
RETURN n;
ELSE
RETURN fibonacci(n - 1) + fibonacci(n - 2);
END
BEGIN
i = 0;
WHILE (i < 10)
DO
BEGIN
o = fibonacci(i);
SUSPEND;
i = i + 1;
END
END!
BEGIN … END
Обозначение составного оператора.
PSQL.
<block> ::= BEGIN [<compound_statement> ...] END <compound_statement> ::= {<block> | <statement>}
Операторные скобки BEGIN … END
определяют составной оператор или блок операторов, который выполняется как одна единица кода.Каждый блок начинается оператором BEGIN
и завершается оператором END
.Блоки могут быть вложенными.Максимальная глубина ограничена 512 уровнями вложенности блоков.Составной оператор может быть пустым, что позволяет использовать его как заглушку, позволяющую избежать написания фиктивных операторов.
После операторов BEGIN
и END
точка с запятой не ставится.Однако утилита командной строки isql
требует, чтобы после последнего оператора END в определении PSQL модуля следовал символ терминатора, установленного командой SET TERM.Терминатор не является частью синтаксиса PSQL.
Последний оператор END в триггере завершает работу триггера.Последний оператор END в хранимой процедуре работает в зависимости от типа процедуры:
В селективной процедуре последний оператор END возвращает управление приложению и устанавливает значение SQLCODE равным 100, что означает, что больше нет строк для извлечения;
В выполняемой процедуре последний оператор END возвращает управление и текущие значения выходных параметров, если таковые имеются, вызывающему приложению.
BEGIN … END
Пример процедуры из базы данных employee.fdb
, демонстрирующий простое использование блоков BEGIN … END
:
BEGIN … END
SET TERM ^;
CREATE OR ALTER PROCEDURE DEPT_BUDGET (
DNO CHAR(3))
RETURNS (
TOT DECIMAL(12,2))
AS
DECLARE VARIABLE SUMB DECIMAL(12,2);
DECLARE VARIABLE RDNO CHAR(3);
DECLARE VARIABLE CNT INTEGER;
BEGIN
TOT = 0;
SELECT
BUDGET
FROM
DEPARTMENT
WHERE DEPT_NO = :DNO
INTO :TOT;
SELECT
COUNT(BUDGET)
FROM
DEPARTMENT
WHERE HEAD_DEPT = :DNO
INTO :CNT;
IF (CNT = 0) THEN
SUSPEND;
FOR
SELECT
DEPT_NO
FROM
DEPARTMENT
WHERE HEAD_DEPT = :DNO
INTO :RDNO
DO
BEGIN
EXECUTE PROCEDURE DEPT_BUDGET(:RDNO)
RETURNING_VALUES :SUMB;
TOT = TOT + SUMB;
END
SUSPEND;
END^
SET TERM ;^
IF … THEN … ELSE
Условный переход.
PSQL
IF (<condition>) THEN <compound_statement> [ELSE <compound_statement>]
Параметр | Описание |
---|---|
condition |
Логическое условие возвращающее TRUE, FALSE или UNKNOWN. |
compound_statement |
Составной оператор (оператор или блок операторов). |
Оператор условного перехода IF
используется для выполнения ветвления процесса обработки данных в PSQL.Если условие возвращает значение TRUE
, то выполняется составной оператор или после ключевого слова THEN.Иначе (если условие возвращает FALSE
или UNKNOWN
) выполняется составной оператор после ключевого слова ELSE, если оно присутствует.Условие всегда заключается в круглые скобки.
PSQL не обеспечивает более сложных переходов с несколькими ветвями, таких как CASE
или SWITCH
.Однако можно объединить операторы IF … THEN … ELSE
в цепочку, см. Раздел примеров ниже.В качестве альтернативы, оператор CASE
из DSQL доступен в PSQL и может удовлетворить по крайней мере некоторые варианты использования в виде switch:
CASE <test_expr> WHEN <expr> THEN <result> [WHEN <expr> THEN <result> ...] [ELSE <defaultresult>] END CASE WHEN <bool_expr> THEN <result> [WHEN <bool_expr> THEN <result> ...] [ELSE <defaultresult>] END
CASE
в PSQL....
C = CASE
WHEN A=2 THEN 1
WHEN A=1 THEN 3
ELSE 0
END;
...
IF
IF
Предположим, что переменные FIRST, LINE2 и LAST были объявлены ранее.
...
IF (FIRST IS NOT NULL) THEN
LINE2 = FIRST || ' ' || LAST;
ELSE
LINE2 = LAST;
...
IF … THEN … ELSE
в цепочкуПредположим, что переменные INT_VALUE и STRING_VALUE были объявлены ранее.
...
IF (INT_VALUE = 1) THEN
STRING_VALUE = 'one';
ELSE IF (INT_VALUE = 2) THEN
STRING_VALUE = 'two';
ELSE IF (INT_VALUE = 3) THEN
STRING_VALUE = 'three';
ELSE
STRING_VALUE = 'too much';
...
Этот пример можно заменить на функциюПростой CASE
или DECODE
.
WHILE … DO
Циклическое выполнение операторов.
PSQL
[label:] WHILE (<condition>) DO <compound_statement>
Параметр | Описание |
---|---|
condition |
Логическое условие возвращающее TRUE, FALSE или UNKNOWN. |
compound_statement |
Составной оператор (оператор или блок операторов). |
Оператор WHILE
используется для организации циклов в PSQL.Составной оператор будет выполняться до тех пор, пока условие истинно (возвращает TRUE). Циклы могут быть вложенными, глубина вложения не ограничена.
WHILE … DO
Процедура расчёта суммы от 1 до I для демонстрации использования цикла:
CREATE PROCEDURE SUM_INT (I INTEGER)
RETURNS (S INTEGER)
AS
BEGIN
s = 0;
WHILE (i > 0) DO
BEGIN
s = s + i;
i = i - 1;
END
END
При выполнении в isql:
EXECUTE PROCEDURE SUM_INT(4);
результат будет следующий
S ========== 10
BREAK
Выход из цикла.
<loop_stmt> BEGIN ... BREAK; ... END <loop_stmt> ::= FOR <select_stmt> INTO <var_list> DO | FOR EXECUTE STATEMENT ... INTO <var_list> DO | WHILE (<condition>) DO
Параметр | Описание |
---|---|
select_stmt |
Оператор |
condition |
Логическое условие возвращающее TRUE, FALSE или UNKNOWN. |
Оператор BREAK
моментально прекращает работу внутреннего цикла операторов WHILE
или FOR
.Код продолжает выполняться с первого оператора после завершенного блока цикла.
Оператор BREAK
похож на LEAVE
, за исключением того, что не поддерживает метку перехода.
Note
|
Этот оператор считается устаревшим.Начиная с Firebird 1.5 рекомендуется использовать SQL-99 совместимый оператор LEAVE. |