FirebirdSQL logo

Обработка ошибок

В Firebird существуют PSQL операторы для обработки ошибок и исключений в модулях.Существует множество встроенных исключений, которые возникают в случае возникновения стандартных ошибок при работе с DML и DDL операторами.

Системные исключения

Исключение представляет собой сообщение, которое генерируется, когда возникает ошибка.

Все обрабатываемые Firebird исключения имеют заранее определённые числовые (символьные) значение для контекстных переменных и связанные с ними тексты сообщений.Сообщения об ошибке написаны по умолчанию на английском языке.Существуют и локализованные сборки СУБД, в которых сообщения об ошибках переведены на другие языки.

Полный список системных исключений вы можете найти в приложении "Обработка ошибок, коды и сообщения":

docnext count = 18

Пользовательские исключения

Пользовательские исключения могут быть объявлены в базе данных как постоянные объекты и вызваны из PSQL кода для сообщения об ошибке при нарушении некоторых бизнес правил.Текст пользовательского исключения ограничен 1021 байтом.Подробности см. CREATE EXCEPTION.

В коде PSQL исключения обрабатываются при помощи оператора WHEN.Если исключение будет обработано в вашем коде, то вы обеспечите исправление или обход ошибки и позволите продолжить выполнение, то клиенту не возвращается никакого сообщения об исключении.

Исключение приводит к прекращению выполнения в блоке.Вместо того чтобы передать выполнение на конечный оператор END, теперь процедура отыскивает уровни во вложенных блоках, начиная с блока где была вызвана ошибка, и переходит на внешние блоки, чтобы найти код обработчика, который “знает” о таком исключении.Она отыскивает первый оператор WHEN, который может обработать эту ошибку.

EXCEPTION

Назначение

Возбуждение пользовательского исключения или повторный вызов исключения.

Доступно в

PSQL

Синтаксис
EXCEPTION [
    exception_name
    [ custom_message | USING (<value_list>)]
  ]

<value_list> ::= <val> [, <val> ...]
Table 1. Параметры оператора EXCEPTION
Параметр Описание

exception_name

Имя исключения.

custom_message

Альтернативный текст сообщения, выдаваемый при возникновении исключения.Максимальная длина текстового сообщения составляет 1021 байт.

val

Значения, которыми заменяются слоты в тексте сообщения исключения.

Оператор EXCEPTION возбуждает пользовательское исключение с указанным именем.При возбуждении исключения можно также указать альтернативный текст сообщения, который заменит текст сообщения заданным при создании исключения.

Текст сообщения исключения может содержать слоты для параметров, которые заполняются при возбуждении исключения.Для передачи значений параметров в исключение используется предложение USING.Параметры рассматриваются слева направо.Каждый параметр передаётся в оператор возбуждающий исключение как “N-ый”, N начинается с 1:

  • Если N-ый параметр не передан, его слот не заменяется;

  • Если передано значение NULL, слот будет заменён на строку “*** null ***”;

  • Если количество передаваемых параметров будет больше, чем содержится в сообщении исключения, то лишние будут проигнорированы;

  • Максимальный номер параметра равен 9;

  • Общая длина сообщения, включая значения параметров, ограничена 1053 байтами.

Note

Статус вектор генерируется, используя комбинацию кодов isc_except, <exception number>, isc_formatted_exception, <formatted exception message>, <exception parameters>.

Поскольку используется новый код ошибки (isc_formatted_exception), клиент должен быть версии 3.0 или по крайней мере использовать firebird.msg от версии 3.0 для того чтобы правильно преобразовать статус вектор в строку.

Warning

Если в тексте сообщения, встретится номер слота параметра больше 9, то второй и последующий символ будут восприняты как литералы.Например, @10 будет воспринято как @1 после которого следует литерал ‘0’.

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

Пользовательские исключения хранятся в системной таблице RDB$EXCEPTIONS.

Примеры EXCEPTION

Example 1. Вызов исключения
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
Example 2. Вызов исключения с заменой исходного сообщения альтернативным
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
Example 3. Использование параметризованного исключения
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^
См. также:

CREATE EXCEPTION, WHEN …​ DO.

WHEN …​ DO

Назначение

Обработка ошибок.

Доступно в

PSQL

Синтаксис
WHEN {<error> [, <error> ...] | ANY}
DO <compound_statement>

<error> ::= {
    EXCEPTION exception_name
  | SQLCODE number
  | GDSCODE errcode
  | SQLSTATE 'sqlstate_code'
}
Table 1. Параметры оператора WHEN …​ DO
Параметр Описание

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 GDSCODE вы должны использовать символьные имена — такие, как grant_obj_notfound и т.д.Но в составном операторе, после ключевого слова DO доступна контекстная переменная GDSCODE, которая содержит целое число.Для сравнения его с определённой ошибкой вы должны использовать числовое значение, например, 335544551 для grant_obj_notfound.

Оператор WHEN …​ DO вызывается только в том случае, если произошло одно из указанных в его условии событий.В случае выполнения оператора (даже если в нем фактически не было выполнено никаких действий) ошибка или пользовательское исключение не прерывает и не отменяет действий триггера или хранимой процедуры, где был выдан этот оператор, работа продолжается, как если бы никаких исключительных ситуаций не было.Однако в этом случае будет отменено действие DML оператора (SELECT, INSERT, UPDATE, DELETE, MERGE), который вызвал ошибку и все ниже находящиеся операторы в том же блоке операторов не будут выполнены.

Important

Если ошибка вызвана не одним из DML операторов (SELECT, INSERT, UPDATE, DELETE, MERGE), то будет отменен не только оператор вызвавший ошибку, а весь блок операторов.Кроме того, действия в операторе WHEN …​ DO так же будут откачены.Это относится также и к оператору выполнения хранимой процедуры EXECUTE PROCEDURE.Подробнее смотри в CORE-4483.

Область действия оператора WHEN …​ DO

Оператор перехватывает ошибки и исключения в текущем блоке операторов.Он также перехватывает подобные ситуации во вложенных блоках, если эти ситуации не были в них обработаны.

Оператор WHEN …​ DO видит все изменения, произведённые до оператора вызвавшего ошибку.Однако если вы попытаетесь запротоколировать их в автономной транзакции, то эти изменения будут не доступны, поскольку на момент старта автономной транзакции, транзакция, в которой произошли эти изменения, не подтверждена.

Примеры использования WHEN…​DO

Example 1. Замена стандартной ошибки своей.
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 ^;
Example 2. Регистрация ошибке в журнале и повторное её возбуждение в блоке 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
Example 3. Обработка в одном 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
...
Example 4. Перехват ошибок по коду 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>);
Table 1. Параметры оператора DECLARE …​ CURSOR
Параметр Описание

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, используемой в операторе SELECT, изменяется во время выполнения цикла, то её новое значение может (но не всегда) использоваться при выборке следующих строк.Лучше избегать таких ситуаций.Если вам действительно требуется такое поведение, то необходимо тщательно протестировать код и убедиться, что вы точно знаете, как изменения переменной влияют на результаты выборки.Особо отмечу, что поведение может зависеть от плана запроса, в частности, от используемых индексов.В настоящее время нет строгих правил для таких ситуаций, но в новых версиях Firebird это может измениться.

Примеры использования именованного курсора

Example 1. Объявление именованного курсора
CREATE OR ALTER TRIGGER TBU_STOCK
BEFORE UPDATE ON STOCK
AS
  -- Объявление именованного курсора
  DECLARE C_COUNTRY CURSOR FOR (
    SELECT
      COUNTRY,
      CAPITAL
    FROM COUNTRY
  );
BEGIN
  /* Операторы PSQL */
END
Example 2. Объявление прокручиваемого курсора
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
См. также:

OPEN,FETCH,CLOSE,FOR SELECT.

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> ::=
  См. Синтаксис тела модуля
Table 1. Параметры оператора DECLARE PROCEDURE
Параметр Описание

subprocname

Имя подпроцедуры.

inparam

Описание входного параметра.

outparam

Описание выходного параметра.

Оператор DECLARE PROCEDURE объявляет или реализует подпроцедуру.

На подпроцедуру накладываются следующие ограничения:

  • Подпрограмма не может быть вложена в другую подпрограмму. Они поддерживаются только в основном модуле (хранимой процедуре, хранимой функции, триггере и анонимном PSQL блоке);

  • Переменные из основного модуля доступны внутри подпрограммы;

  • При чтении переменные и параметры, к которым обращаются подпрограммы, могут иметь небольшое снижение производительности (даже в основной программе).

  • В настоящее время подпрограмма не имеет прямого доступа до курсоров из основного модуля. Это может быть разрешено в будущем.

Одна подпрограмма может вызывать и другую подпрограмму, в том числе рекурсивно.В ряде случаев может потребоваться предварительное объявление подпрограммы.Общее правило: одна подпрограмма может вызвать другую подпрограмму, если последняя объявлена выше точки вызова.Все объявленные подпрограммы должны быть реализованы с той же сигнатурой.Значения по умолчанию для параметров подпрограмм не могут быть переопределены.Это означает, что они могут быть определены в реализации только тех подпрограмм, которые не были объявлены ранее.

Example 1. Использование подпроцедуры
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^
Example 2. Использование подпроцедур с предварительным объявлением
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!
См. также:

DECLARE FUNCTION,CREATE PROCEDURE.

DECLARE FUNCTION

Назначение

Объявление и реализация подфункции.

Доступно в

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> ::=
  См. Синтаксис тела модуля
Table 1. Параметры оператора DECLARE FUNCTION
Параметр Описание

subfuncname

Имя подфункции.

inparam

Описание входного параметра.

type

Тип выходного результата.

collation

Порядок сортировки.

Оператор DECLARE FUNCTION объявляет подфункцию.

На подфункцию накладываются следующие ограничения:

  • Подпрограмма не может быть вложена в другую подпрограмму. Они поддерживаются только в основном модуле (хранимой процедуре, хранимой функции, триггере и анонимном PSQL блоке);

  • Переменные из основного модуля доступны внутри подпрограммы;

  • При чтении переменные и параметры, к которым обращаются подпрограммы, могут иметь небольшое снижение производительности (даже в основной программе).

  • В настоящее время подпрограмма не имеет прямого доступа до курсоров из основного модуля. Это может быть разрешено в будущем.

Одна подпрограмма может вызывать и другую подпрограмму, в том числе рекурсивно.В ряде случаев может потребоваться предварительное объявление подпрограммы.Общее правило: одна подпрограмма может вызвать другую подпрограмму, если последняя объявлена выше точки вызова.Все объявленные подпрограммы должны быть реализованы с той же сигнатурой.Значения по умолчанию для параметров подпрограмм не могут быть переопределены.Это означает, что они могут быть определены в реализации только тех подпрограмм, которые не были объявлены ранее.

Example 1. Использование подфункции
--
-- Подфункция внутри хранимой функции
--
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 ^
Example 2. Использование рекурсивной подфункции
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!
См. также:

DECLARE PROCEDURE,CREATE FUNCTION.

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:

Example 1. Использование 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 ;^
См. также:

EXIT, LEAVE, SET TERM.

IF …​ THEN …​ ELSE

Назначение

Условный переход.

Доступно в

PSQL

Синтаксис
IF (<condition>)
  THEN <compound_statement>
  [ELSE <compound_statement>]
Table 1. Параметры оператора IF …​ THEN …​ ELSE
Параметр Описание

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
Example 1. Использования CASE в PSQL.
...
C = CASE
      WHEN A=2 THEN 1
      WHEN A=1 THEN 3
      ELSE 0
    END;
...

Примеры IF

Example 1. Использование оператора IF

Предположим, что переменные FIRST, LINE2 и LAST были объявлены ранее.

...
IF (FIRST IS NOT NULL) THEN
  LINE2 = FIRST || ' ' || LAST;
ELSE
  LINE2 = LAST;
...
Example 2. Объединение 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, CASE.

WHILE …​ DO

Назначение

Циклическое выполнение операторов.

Доступно в

PSQL

Синтаксис
[label:]
WHILE (<condition>) DO
  <compound_statement>
Table 1. Параметры оператора WHILE …​ DO
Параметр Описание

condition

Логическое условие возвращающее TRUE, FALSE или UNKNOWN.

compound_statement

Составной оператор (оператор или блок операторов).

Оператор WHILE используется для организации циклов в PSQL.Составной оператор будет выполняться до тех пор, пока условие истинно (возвращает TRUE). Циклы могут быть вложенными, глубина вложения не ограничена.

Примеры WHILE …​ DO

Example 1. Использование оператора 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
Table 1. Параметры оператора BREAK
Параметр Описание

select_stmt

Оператор SELECT

condition

Логическое условие возвращающее TRUE, FALSE или UNKNOWN.

Оператор BREAK моментально прекращает работу внутреннего цикла операторов WHILE или FOR.Код продолжает выполняться с первого оператора после завершенного блока цикла.

Оператор BREAK похож на LEAVE, за исключением того, что не поддерживает метку перехода.

Note

Этот оператор считается устаревшим.Начиная с Firebird 1.5 рекомендуется использовать SQL-99 совместимый оператор LEAVE.

См. также:

LEAVE, EXIT, CONTINUE.