|
ABL блоки
Обработчик ошибок ABL запускается на уровне операторов и работает в пределах ближайшего блока. Стандартные свойства блока и опции операторов определяют способы обработки ошибок.Типы блоков
Блок ABL – это набор ABL операторов выполняемых как единый модуль. Блок состоит из определения блока, тела блока (набор ABL операторов) и завершающего утверждения END. Выполнение тела блока определяется типом блока, встроенными свойствами блока, и для большего эффекта - опциями блока. Все ABL операторы должны содержаться в блоке. ABL блоки могут быть сгруппированы по следующим типам: Basic blocks, End blocks, Routine-level blocks и Class block.
Basic blocks или основные блоки, обеспечивают фундаментальные процедурные функциональные возможности. Хотя они и обеспечивают потоко-управляемыми опциями (flow-of-control options), они не являются строго вызываемыми модулями, а потому, это не подпрограммы. Основные блоки это DO, FOR и REPEAT.
Эти три блока имеют богатый набор опций, которые позволяют нам создавать различные их разновидности. Вот некоторая важная информация относительно основных блоков:
- Они имеют некоторые ограничения на размещение в ABL коде;
- Поток управления (выполнение переходов) с основными блоками обрабатывается по ссылкам на метки блоков;
- Только основные блоки могут быть повторяемыми;
- Только основные блоки позволяют изменять стандартный обработчик ошибок с помощью ON ERROR;
- Блок DO, без каких либо опций, не имеет ни каких стандартных свойств и называется простым DO-блоком. Поэтому, он не содержит ни какого обработчика ошибок, если конечно он не является DO TRANSACTION блоком или DO ON ERROR блоком.
End blocks, или конечные блоки, это блоки которые определяют способы завершения работы блока, которые их содержит. Такие блоки всегда являются частью другого блока, который называется associated block или связный блок. Конечные блоки должны определяться после последнего оператора в связном блоке и до указания утверждения END. Конечными блоками являются блок CATCH и FINALLY. Вот некоторая важная информация относительно этих блоков:
- CATH блок определяет пользовательский обработчик ошибок и является строгой характеристикой модели структурного обработчика ошибок;
- FINALLY блок содержит код, который должен быть выполнен при корректном завершении работы связного блока или в случае ошибки. FINALLY является важной характеристикой структурного обработчика ошибок. Использование FINALY блоков с традиционным обработчиком ошибок не изменяет поведение традиционной модели обработки ошибок;
- FINNALY блок должен размещаться последним END блоком.
Routine-level blocks. Routine или подпрограмма, это модуль с кодом, который может быть вызван или запущен из другого модуля, ссылаясь на обычное имя. Такие блоки в ABL могут вызываться различными способами:
- Запуск оператором RUN;
- Вызов событием базы данных или событием пользовательского интерфейса (триггеры);
- По связи с присваиванием или выражением;
- Доступ из object handle.
Routine-level blocks это:
- Процедуры, так же называемые внешними процедурами или .p файлами;
- Внутренние процедуры;
- Пользовательские функции;
- Процедуры триггеров базы данных (.p файл), блоки триггеров базы данных (события ON database-event);
- Метод класса (пользовательский метод), конструктор, деструктор, средства доступа (методы GET и SET).
Имеются некоторые важные факты относительно routine-level блоков:
- Файл процедур имеет неявный блок, который содержит весь код, содержащийся в этой процедуре. Представьте неявный блок как невидимый блок операторов и невидимое END утверждение. Конечные блоки (End blocks) помещенные в конце файла процедуры принадлежат этому неявному процедурному блоку;
- В то время как внутренние процедуры и определяемые пользователем функции определены в процедурном блоке, во время выполнения, эти обычные блоки становятся подблоками кода, который вызывает подпрограмму. Другими словами, подпрограммы не определены в процедурном блоке;
- Процедурный файл триггера базы данных (.p) является блоком с явным заголовком блока и неявным оператором END. Если вы добавите оператор END после end–блоков, то компилятор сгенерирует ошибку.
- Триггер в пользовательском интерфейсе можно вызвать, используя синтаксис APPLY event-name
Class blocks, или блоки класса (.cls), которые являются основой объектно-ориентированного программирования в ABL, не являются выполняемыми программами в том же смысле, как и другие ABL блоки, которые по своей природе являются процедурными. Блок класса определяет абстрактный объект и его членов. В пределах этих блоков используются следующие типы стандартных блоков:
- Методы, определяемые пользователем;
- Конструкторы;
- Деструкторы;
- Свойства средств доступа (свойства методов GET и SET).
В следующей таблице приведено описание каждого ABL блока, включая общее название, тип и ABL оператор, используемый для его определения.
Название блока |
Тип |
Определение |
Одиночный блок DO |
Basic |
Используется без
опции TRANSACTION
или без фразы ON ERROR |
Блок DO
TRANSACTION |
Basic |
Используется
оператор DO
с опцией TRANSACTION |
Блок DO
ON ERROR |
Basic |
Оператор DO
с фразой ON ERROR |
Блок FOR |
Basic |
Оператор FOR |
Блок REPEAT
|
Basic |
Оператор REPEAT |
Блок CATCH
(только для структурного обработчика ошибок) |
End |
Оператор CATCH |
Блок FINALLY
(традиционный или структурный обработчик ошибок) |
End |
Оператор FINALLY |
Procedure
(внешняя процедура) |
Routine-level
(файл) |
Все неявные блоки в
процедурном файле |
Внутренняя процедура |
Routine-level |
Оператор PROCEDURE |
Пользовательская
функция |
Routine-level |
Оператор FUNCTION |
Процедура триггера
базы данных |
Routine-level |
Оператор TRIGGER PROCEDURE
в процедурном файле |
Триггерный блок базы
данных |
Routine-level |
Оператор ON
с указанием события базы данных |
Триггер
пользовательского интерфейса |
Routine-level |
Оператор ON
с указанием события пользовательского интерфейса |
Метод класса
(пользовательский метод) |
Routine-level |
Оператор METHOD |
Конструктор класса |
Routine-level |
Оператор CONSTRUCTOR |
Деструктор класса |
Routine-level |
Оператор DESTRUCTOR |
Свойство средств
доступа класса |
Routine-level |
Оператор PROPERTY
и определения GET
и SET |
Блок класса (файл
класса) |
Class (файл) |
Оператор CLASS
в файле класса (.cls) |
Концепция UNDO
ABL UNDO, гарантирует, что все ожидающие обработки изменения постоянных данных (поля базы данных) не будут закреплены в базе данных если возникнут события ERROR или STOP. Поскольку ABL транзакционно - ориентирован, то набор ожидающих обработки изменений эквивалентен открытой (текущей) транзакции. UNDO по существу “выбрасывает” текущую транзакцию.
ABL так же распространяет UNDO-защиту на такие данные, как поля временных таблиц и переменные. По умолчанию, ABL создает переменные и временные таблицы как отменяемые. Если в блоке имеются отменяемые переменные или поля, то AVM отменит (undoes) все изменения этих данных, не зависимо от того, является ли блок транзакционным или нет. Процесс UNDO для переменных и временных таблиц связан с дополнительной нагрузкой, поэтому старайтесь, на сколько это возможно, определять переменные и временные таблицы с указанием опции NO-UNDO. С этой опцией, AVM не будет отслеживать изменения таких данных, а следовательно, любое действие UNDO будет игнорировать их.
Транзакции ограничены пределами блока. Стандартный обработчик ошибок так же ограничен пределами блока, и первые шаг, выполняемый обработчиком ошибок, это выполнение UNDO. Таким образом, отмена транзакции (undoing a transaction) является синонимом отмены всего блока (undoing a block). Фактически, единственное что делается, это отменяются изменения в полях базы данных, в переменных и во временных таблицах, у которых не указано NO-UNDO. Другие действия, вызванные операторами и подпрограммами, не отменяются. Блок является транзакционным, только если он содержит один из следующих операторов, связанных с полем базы данных:
- CREATE
- DELETE
- ASSIGN (и оператор присваивания “=” )
- INSERT
- SET
- UPDATE
Операторы, которые выполняют выборку из базы данных в EXCLUSIVE-LOCK.
Если блок операторов использует опцию TRANSACTION, то это тоже будет транзакционный блок. Эта опция вынудит ABL создать транзакцию для отменяемых (UNDO) переменных и полей временных таблиц, даже если в блоке не выполняется изменение полей базы данных. Для того чтобы проверить, какие блоки в вашей программе являются транзакционными, вы можете воспользоваться опцией компилятора LISTING.
Понимание транзакций является важной предпосылкой к пониманию стандартного обработчика ошибок. У вас должно быть хорошее понимание того, как определить транзакции и субтранзакции, и вы должны точно смоделировать деловую логику вашего приложения перед началом работы.
Опции перехода
После того как блок выполнит операцию UNDO, AVM должен определить, какое действие необходимо выполнить далее. Для этого в ABL есть несколько различных опций, таких как:
- RETRY – если блок содержит логику ввода данных пользователем, RETRY повторит итерацию блока. RETRY полезен, когда вы хотите дать своим пользователям еще один шанс для корректного введения данных. Поскольку современная практика программирования рекомендует отделять логику пользовательского интерфейса от транзакционной логики, то RETRY обычно не используется.
- LEAVE – указывает AVM на выход из блока и на выполнение следующего оператора.
- NEXT – указывает AVM на выход из текущей итерации блока и продолжить со следующей итерации. Если следующей итерации не будет, то NEXT становится эквивалентом LEAVE.
- RETURN – указывает AVM на необходимость выхода из блока, и далее на немедленный выход из подпрограммы. Т.е. выполнение возобновляется в вызывающей программе. Если вызывающей программы не существует, то приложение завершается. RETURN имеет множество собственных опций, о которых будет рассказано позже.
- THROW – (Структурный обработчик ошибок) Указывает AVM, что он должен подавить ошибку, выйти из блока и передать объект ошибки в вызывающую программу или в следующий блок.
Каждый тип блока имеет значения перехода по умолчанию, которые описаны в следующей таблице:
Тип блока |
Если обнаружен
ввод данных пользователем |
Если итерация |
Прочее |
DO
TRANSACTION |
RETRY |
NEXT |
LEAVE |
FOR |
RETRY |
NEXT |
- |
REPEAT |
RETRY |
NEXT |
LEAVE |
End
blocks |
- |
- |
THROW |
Routine-level
blocks |
RETRY |
- |
LEAVE |
Trigger
procedure file |
RETRY |
- |
RETURN
ERROR |
Оператор UNDO
Часто возникают ситуации, когда вам необходимо отменить транзакцию, если бизнес-логика обнаружила ошибку не связанную с базой данных. Оператор UNDO позволит вам отменить текущую транзакцию и указать способ перехода к следующему действию. Синтаксис оператора следующий:
UNDO [ label ]
[ , LEAVE [ label2 ]
| , NEXT [ label2 ] | , RETRY [ label1 ] | , RETURN [ return-value | ERROR [ return-value | error-object-expression ] | NO-APPLY ] | , THROW error-object-expression ]
Обратите внимание на параметр синтаксиса label. Если заголовок оператора имеет метки (label) для ваших блоков, то вы можете использовать их для управления тем, какой блок выполняет UNDO, какой должен выполнить LEAVE, а какой NEXT. Метки позволяют вам контролировать отмену транзакций при работе с вложенными блоками. Если вы используете LEAVE label2 или NEXT label2, то label2 не может быть блоком за пределами возможности UNDO. Более подробно UNDO будет описан позже.
|