Этот сайт посвящается администрированию баз данных OpenEdge Progress.
Не корысти ради, а познания для!

С уважением,
Валерий Башкатов
Сайт разработан при участии компании Progress Technologies, официального дистрибьютора Progress Software Corp. на территории стран СНГ и Латвии.

RSS RSS подписка на обновления сайта

Поиск по сайту

Лучшие материалы

Orphus System
На сайте функционирует система коррекции ошибок. Обнаружив неточность в тексте, выделите её и нажмите Ctrl+Enter



Результаты опроса: Нужны ли книги по Progress OpenEdge на русском языке? (опрос проводился с мая 2009 по ноябрь 2010)

Да, нужны. Потому что будет легче понять материал - 268
Нет, не нужны. Достаточно материалов на английском языке - 10
Не знаю, мне всё равно - 6

А знаете ли вы что..



Традиционная обработка ошибок



Язык ABL всегда был процедурным языком баз данных. И имел способность смешивания логики процедур, баз данных и пользовательского интерфейса в одном файле. Семантика работы с базой данных подразумевает, что обработка ABL ошибок защищает постоянные данные, используя управление транзакциями. Обработчик ошибок использует возможности ABL, чтобы увеличить шанс восстановления работы приложения после ошибки.

Язык ABL обеспечивает поддержку объектно-ориентированного программирования и прочие интеграционные особенности с другими возможностями платформ OpenEdge. Следовательно, существует множество различных способов обработки ошибок. Традиционная модель обеспечивает удобный в работе набор возможностей в ABL. Что так же обеспечивает стандартные способы связи ABL ошибок между различными интеграционными возможностями OpenEdge. Например, Web сервис возвращает ошибку как ошибку промышленного стандарта SOAP. Традиционная модель позволяет вашему приложению обработать такую ошибку как системную ABL ошибку.

Для того чтобы хорошо понять традиционную модель обработки ошибок, вам необходимо разобраться в следующем:

 

  • Как конкретный оператор обрабатывает ошибку;
  • Понимать сообщения OpenEdge;
  • Как конкретный блок обрабатывает ошибку;
  • Как использовать опции оператора блока, чтобы изменить стандартную обработку ошибок;
  • Как подавлять системные ошибки с помощью NO-ERROR;
  • Как проверить наличие ошибок после NO-ERROR, и как перейти к собственной логике обработки ошибки;
  • Как использовать ERROR;
  • Как явно можно отменять транзакции;
  • Понимать условную обработку с использованием STOP и QUIT.

 Ошибки операторов

В ABL, когда AVM не в состоянии должным образом выполнить оператор, обычно возникает событие ERROR. На приведенном ранее примере, вы видели, что оператор FIND, не найдя соответствующую запись, создает такое событие. Если отказ работы оператора достаточно серьезен, то AVM может вместо ERROR создать событие STOP. Например, оператор RUN, который не может найти указанный файл процедуры, создаст событие STOP. В некоторых случаях, операторы могут не создавать события ERROR, например, оператор MESSAGE.

Операторы ABL проектировались так, что бы иметь возможность реагировать на различные возникающие события. Реакция всегда основывается на ее уместности с учетом цели оператора. Например:

  •  Не удачная работа оператора FIND означает, что записи с данными не были найдены, а следовательно, они не будут доступны операторам, следующим за FIND. В этом случае уместно создание событие ERROR;
  • Сбой при работе оператора RUN указывает на отсутствие функциональной возможности, соответственно, здесь уместно остановить работу приложения;
  • Оператор MESSAGE предоставляет диагностическую информацию или обратную связь с пользователем. Поэтому, имеет смысл отображать как можно больше информации насколько возможно, даже если бы AVM не смог бы обеспечить этот вывод. Поэтому оператор MESSAGE и не создает события ERROR.

Если вы используете какой-либо оператор впервые, то не полениться обратиться к документации для того, чтобы понять, как им обрабатываются возможные ошибки. Это особенно важно для более специализированных операторов и системных объектных методов. У некоторых их них могут быть дополнительные поведения при обработке ошибок, или по отношению к традиционной модели обработки ошибок, могут быть расширены функциональные возможности.

Поведение оператора относительно поведения блока

Рассмотрим следующую процедуру:

/* Этот оператор во время работы сгенерирует состояние ERROR */
FIND FIRST Customer WHERE CustNum = 1000.
/* Поэтому этот оператор не будет запущен */
FIND FIRST Customer WHERE CustNum = 2000.

Первый оператор потерпит неудачу, поскольку база данных Sports2000 не содержит необходимую запись. Когда это произойдет, AVM остановит выполнение блока на неудачном операторе. Другими словами, если за этим оператором будет следовать другой оператор, то он не будет выполнен.

AVM на экране отобразит следующее сообщение, в качестве сообщения по умолчанию:

 

 Это также проводит линию между обработкой ошибок на уровне оператора и обработкой ошибок на уровне блока. Следующие действия, AVM будет предпринимать, основываясь на стандартных свойствах обработки ошибок блока или на опциях блока оператора. Опции блока оператора не могут повлиять на остановку выполнения или на отображение стандартного сообщения об ошибке. Только опция NO-ERROR, указанная оператору может сделать это.

Стандартная обработка ошибок для блока с UNDO, сопровождается операторами RETRY или LEAVE. В предыдущем примере не было ни какого пользовательского ввода данных, поэтому по умолчанию метод перехода будет LEAVE. Управление будет передано вызывающему процедурному блоку. Если вызывающей программы не существует, то работа ”приложения” будет завершена.

Понимание сообщений OpenEdge

Системные сообщения информируют об ошибках, с которыми сталкивается AVM, выполняя процедуру.

В этом документе, термин “сообщение об ошибке” относится к любому системному сообщению об ошибке в OpenEdge или к любому пользовательскому сообщению об ошибке. В предисловии каждого OpenEdge документа содержатся стандартные инструкции для того чтобы получить доступ к информации по сообщениям. В системе OpenEdge Architect имеется подробный “Help” по каждому сообщению об ошибках. Сообщение об ошибке идентифицируется текстовой строкой и номером ошибки, как показано на следующем рисунке:

Error string Error number
**FIND FIRST/LAST failed for table Customer (565)

По номеру сообщения вы всегда можете найти подробное описание ошибки и необходимые действия по её устранению.

Определение поведения обработчика ошибок

Для того чтобы изменить стандартную обработку ошибок для базовых блоков, в ABL существует фраза NO ERROR. Ниже приведен ее синтаксис:

ON ERROR UNDO
     [ label1 ]
     [ , LEAVE [ label2 ]
          | , NEXT [ label2 ]
          | , RETRY [ label1 ]
          | , RETURN [ return-value |
               ERROR [ return-value | error-object-expression ] |
               NO-APPLY ]
          | , THROW
     ]

Опции этого синтаксиса почти такие же, как и у оператора UNDO.

Здесь,

label1, имя блока, деятельность которого вы хотите отменить. Если вы не укажите имя блока в label1, ON ERROR UNDO отменит действия текущего блока, содержащего фразу ON ERROR.

LEAVE [label2], указывает на то, что после отмены действий блока, AVM должен выйти из блока, который помечен меткой label2. Если блок не именован, AVM покинет блок, помеченный меткой label1.

NEXT [label2], Указывает, что после отмены действий блока, AVM запустит следующую итерацию блока помеченного меткой label2. Если блок не использует имя с опцией NEXT, AVM запустит следующую итерацию блока помеченного меткой label1.

RETRY [label1], указывает, что после отмены действий блока, AVM повторит туже итерацию блока, помеченного меткой label1. Если явно не указаны опции LEAVE, NEXT, RETRY или RETURN, то опция RETRY используется по умолчанию. Поскольку RETRY в блоке, в котором нет операций пользовательского ввода, может привести к бесконечному циклу, AVM автоматически анализирует возникновение такой возможности, и в случае необходимости, преобразовывает блок RETRY в блок LEAVE или в блок NEXT, если это итерационный блок. Такой механизм иногда называют “защитой от зацикливания” (infinite loop protection).

RETURN …, возвращение в вызывающую программу или, если таковой нет, то возвращение происходит в OpenEdge Editor. Следующая таблица описывает различные случаи выполнения RETURN.

Опция

Описание

return-value

Возвращение строки вызывающей программе. Для того чтобы вызывающая программа могла прочитать её, она должна использовать функцию RETURN-VALUE. Для определенных пользователями функций, значение должно соответствовать определенному возвращаемому типу.

ERROR

Генерирует ERROR в вызывающей программе и отменяет текущую субтранзакцию.

Нельзя указать ERROR в пределах пользовательского триггерного блока или деструктора.

ERROR return-value

Генерирует ERROR в вызывающей программе и отменяет текущую субтранзакцию, исключение составляют определенные пользователем функции. Текстовая строка, возвращаемая вызывающей программе, доступна через функцию RETURN-VALUE.

В структурном обработчике ошибок, AVM также создает объект AppError и сохраняет return-value в свойстве объекта ReturnValue.

ERROR error-object-expression

В структурном обработчике ошибок, генерирует ERROR в вызываемой программе и отменяет текущую субтранзакцию.

Указанные объект ошибки это ваш код. Если это объект AppError, то вызывающая программа так же может использовать функцию RETURN-VALUE для чтения свойства ReturnValue.

NO-APPLY

В триггере пользовательского интерфейса, предохраняет AVM от выполнения заданных по умолчанию действий для этого события.

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

Опции фразы NO ERROR параллельны свойствам блока, которые определяют обработчик ошибок для блока заданный по умолчанию. У всех блоков, кроме простого блока DO, есть неявная фраза ON ERROR.

Так для процедурного блока, который не поддерживает явно фразу NO ERROR, Вы можете сказать, что процедурный блок содержит неявную фразу ON ERROR. Это неявная фраза - ON ERROR UNDO, LEAVE, если процедурный блок не содержит пользовательских вводов. Если процедурный блок действительно содержит пользовательский ввод, то у него есть неявная фраза - ON ERROR, RETRY.

В дальнейшем, в этом документе используется понятие неявной (или явной) фразы ON ERROR, чтобы описывать свойства обработчика ошибок блока. Это изменение терминологии облегчит сравнение различных блоков, в различных случаях использования.

 Использование меток

Следующий пример, устанавливает единый набор вложенных блоков FOR EACH, который перечисляет порядковые номера для нескольких первых записей в базе Sports2000. В пределах внутреннего блока, бессмысленный оператор FIND сгенерирует ошибку сразу после первой итерации. Эта тривиальная структура позволит протестировать взаимодействия фраз ON ERROR.

Этот вариант демонстрирует, как метка может быть использована для отмены транзакции связанной с внешним блоком, а не только субтранзакции внутреннего блока:

PROCEDURE NestedBlocks:
Outer-Block:
FOR EACH Customer WHERE CustNum < 5:
ASSIGN Customer.Name = Customer.Name + “_changed”.
Inner-Block:
FOR EACH Order OF Customer
ON ERROR UNDO Outer-Block, RETURN:
DISPLAY OrderNum.
/* Nonsense code raises ERROR. */
FIND SalesRep WHERE RepName = Customer.Name.
END. /* Inner-Block */
END. /* Outer-Block */
DISPLAY "For Blocks Complete".
END PROCEDURE.
RUN NestedBlocks.
DISPLAY "Procedure NestedBlocks Complete."

Поток выполнения этого примера следующий:

  • оператор ASSIGN в блоке Outer-Block стартует транзакцию;
  • оператор FIND в блоке Inner-Block генерирует условии ошибки ERROR;
  • блок Inner-Block автоматически отменяется;
  • активируется явная фраза ON ERROR в блоке Inner-Block;
  • отменяется блок Outer-Block;
  • управление возвращается вызывающей программе, которой является основной блок процедуры.

Следующая таблица, содержит список всех фраз ON ERROR, действующих в этой процедуре от самых внешних до внутренних.

Блок

Фраза ON ERROR

Процедурный блок (.p файл)

Неявная, ON ERROR UNDO, LEAVE

Внутренняя процедура NestedBlocks

Неявная, ON ERROR UNDO, LEAVE

Блок FOR EACH помеченный меткой Outer-Block

Неявная, ON ERROR UNDO, NEXT

Блок FOR EACH помеченный меткой Inner-Block

Явная, ON ERROR UNDO Outer-Block, RETURN

Когда AVM генерирует ERROR на первой итерации блока Inner-Block, явная фраза ON ERROR указывает AVM на необходимость отмены внешнего блока Outer-Block и на использование опции перехода RETURN. RETURN в любом месте программы сдерживает возвращение управления в вызывающий блок, который является процедурным файлом. Поскольку опция RETURN не содержит опцию ERROR, то ошибка не возникает в процедурном блоке, что позволяет выполниться последнему оператору DISPLAY.

Если вы измените явно указанную фразу ON ERROR, как указано на следующем отрывке кода, то выполнение программы будет идентичным, за исключением того, что оператор DISPLAY не будет выполнен:

Inner-Block:
FOR EACH Order OF Customer
ON ERROR UNDO Outer-Block, RETURN ERROR:

Сгенерированная ошибка (ERROR) в процедурном блоке возвратит управление в OpenEdge Editor.

Если вы измените явную фразу ON ERROR, используя опцию перехода NEXT, для каждой клиентской записи (Customer), вы будете видеть одну запись Order, сопровождаемую отображением сообщением об ошибке:

Inner-Block:
FOR EACH Order OF Customer
ON ERROR UNDO Outer-Block, NEXT:

В завершении, если вы удалите явную фразу ON ERROR, неявная фраза ON ERROR будет для блока Inner-Block выглядеть так ON ERROR UNDO, NEXT. Операция UNDO будет применена к блоку Inner-Block вместо блока Outer-Block. Вы будете видеть одно сообщение об ошибке для каждой итерации Inner-Block, для каждой записи Customer.

 Подавление ошибок

Для подавления ошибок (ERROR), в ABL используется опция NO-ERROR. Например это может понадобиться в следующих случаях:

  • Чтобы в стандартный вывод не отображать ни каких сообщений;
  • Для выполнения работы следующего оператора;
  • Чтобы не передать управление блоку обработчика ошибок.

Примечание: опция NO-ERROR не имеет ни какого эффекта на обработчик состояния STOP.

Для того чтобы узнать, какие операторы поддерживают опцию, обратитесь к материалу OpenEdge Development: ABL Reference. В некоторых случаях, опция NO-ERROR может расширить стандартное поведение некоторых специфических операторов.

Если возникает ошибка, когда указана опция NO-ERROR, то оператор не выполняется, а выполняется следующий за ним оператор. Если в операторе возникает сбой, то все с ним связанные изменения будут отменены. Если у оператора имеются выражения, которые содержат запускаемые элементы, такие как различные методы, то действия этих элементов могут быть выполнены, а могут, и нет. Всё зависит от порядка обработки AVM элементов выражения и вхождений ошибки.

В следующем примере, внутренняя процедура возвращает контроль в вызывающий процедурный блок с поднятым состоянием ошибки (ERROR). Однако, оператор RUN имеет опцию NO-ERROR. Поэтому, последний оператор DISPLAY будет выполнен, поскольку AVM обработает состояние ERROR, как показано ниже:

PROCEDURE NestedBlocks:
Outer-Block:
FOR EACH Customer WHERE CustNum < 5:
ASSIGN Customer.Name = Customer.Name + “_changed”.
Inner-Block:
FOR EACH Order OF Customer
ON ERROR UNDO Outer-Block, RETURN ERROR:
DISPLAY OrderNum.
/* Nonsense code raises ERROR. */
FIND SalesRep WHERE RepName = Customer.Name.
END.
END.
DISPLAY "For Blocks Complete".
END PROCEDURE.
RUN NestedBlocks NO-ERROR.
DISPLAY "Procedure NestedBlocks Complete."

Этот пример также демонстрирует область видимости опции NO-ERROR, которая применена только к оператору. Да же при том, что оператор RUN в результате запустил подпрограмму, NO-ERROR не имеет отношения к операторам в ней.

Собственная обработка ошибок

Опция NO-ERROR перенаправляет ошибки в системный хэндел (handle) ERROR-STATUS. Он сохраняет каждое системное сообщение об ошибки, которое возникло в операторе с опцией NO-ERROR. Хэндел хранит эту информацию до тех пор, пока AVM не выполнит другой оператор с опцией NO-ERROR, не зависимо от того, возникла ли в нем ошибка или нет.

ERROR-STATUS предоставляет вам возможность проверить, произошла ли какая-либо ошибка или какая-либо конкретная ошибка. В зависимости от типа ошибки, вы могли бы сделать так, чтобы на каждую из них выполнялись различные действия.

Атрибуты и методы системного хендла позволяют вам выполнять различные тесты. Например, если вас интересуют конкретные ошибки, то вам будут полезны номера ошибочных сообщений. Или если, например, вам нужно изменить строку ошибочного сообщения для размещения её в лог–файл, вы так же это можете сделать.

Следующая таблица описывает значимые атрибуты и методы системного хендла ERROR-STATUS. 

Атрибут или метод

Описание

Атрибут ERROR

Если ABL оператор использует опцию NO-ERROR и AVM поднимает состояние ERROR, то этот атрибут получит значение TRUE.

Если метод системного объекта ABL генерирует сообщение ошибки, то AVM не поднимает ошибку и этот атрибут остается в состоянии FALSE.

Атрибут ERROR-OBJECT-DETAIL

Если метод Web сервиса возвращает SOAP ошибку, AVM сохраняет информацию о ней в объекте ABL SOAP-fault и поднимает ERROR. AVM хранит ссылку на объект SOAP-fault в этом атрибуте.

Атрибут NUM-MESSAGES

Предоставляет целое количество всех сообщений об ошибках генерируемых оператором с опцией NO-ERROR.

Метод GET-MESSAGE(index)

Позволяет вам получить строку сообщения указанной ошибки. Index, это число начинающееся от 1 до значения NUM-MESSAGES.

Метод GET-NUMBER(index)

Позволяет вам получить конкретный номер ошибки. Index, это число начинающееся от 1 до значения NUM-MESSAGES.

 Тестирование ошибки оператора.

Следующий пример предполагает, что в случае возникновения ошибки, будет выполнен специальный код программы. Опция NO-ERROR подавляет стандартный ABL обработчик ошибок, а оператор IF запрашивает системный хэндел ERROR-STATUS о возникновении конкретной ошибки. Пример программы смотрите ниже:

DEFINE VARIABLE i AS INTEGER NO-UNDO.
FIND FIRST Customer WHERE CustNum = 1000 NO-ERROR.
IF ERROR-STATUS:ERROR THEN
DO i = 1 TO ERROR-STATUS:NUM-MESSAGES:
IF ERROR-STATUS:GET-NUMBER( i ) = 565 THEN
RUN FailedFindRecovery.p.
IF i = ERROR-STATUS:NUM-MESSAGES THEN
RUN GeneralErrorRecovery.p
END.

Тестирование встроенных предупреждающих методов.

Так как встроенные методы хендла обрабатывают ошибки как предупреждения (warnings), то чтобы обнаружить их, вы не можете использовать IF ERROR-STATUS:ERROR. Однако даже если атрибут ERROR не установлен, сообщения об ошибках всё равно сохраняются в объекте ERROR-STATUS. Поэтому, если ваш оператор содержит ссылочный метод, используйте следующий тест: IF ERROR-STATUS:NUM-MESSAGES > 0. Например:

DEFINE VARIABLE hSocket AS HANDLE.
CREATE SOCKET hSocket.
hSocket:CONNECT ("-H localhost -S 3333") NO-ERROR.
IF ERROR-STATUS:NUM-MESSAGES > 0 THEN
RUN FailedSocketConnect.p.

Отмена действий

Опции оператора UNDO и фраза ON ERROR почти идентичны. Роль оператора UNDO это отмена действий блока, когда логика программы обнаруживает проблему, которая должна быть обработана как ошибка приложения. Поэтому, вам необходим тот же самый набор опций перехода, чтобы обеспечить такой же уровень поддержки обработки ошибок приложения. Позаимствуем тестовый пример из части “Подавление ошибок”. В этом примере удалено явное указание фразы ON ERROR и добавлен бессмысленный тестовый IF, который всегда будет приводить к выполнению оператора UNDO.
PROCEDURE NestedBlocks:
Outer-Block:
FOR EACH Customer WHERE CustNum < 5:
ASSIGN Customer.Name = "changed_" + Customer.Name.
Inner-Block:
FOR EACH Order OF Customer:
DISPLAY OrderNum.
/* Бессмысленный код для тестирования ошибки. */
IF SUBSTRING(Customer.Name, 1, 8) EQ "changed_" THEN
UNDO, RETURN ERROR.
END.
END.
DISPLAY "For Blocks Complete".
END PROCEDURE.
RUN NestedBlocks.
DISPLAY "Procedure NestedBlocks Complete."

Подъем состояния ERROR

Вы уже видели, как можно поднять ERROR с опцией RETURN ERROR фразы ON ERROR и оператора UNDO. Оператор RETURN с опцией ERROR это третий способ поднятия ERROR.
Вообще, оператор RETURN предназначен для быстрого выхода из блока. Это средство для немедленной остановки работы блока и возврата к вызывающему блоку без учета прошедших блоков.
Оператор выходит из локальной или удаленной (remote) процедуры, или из определенного пользователем функционального блока, триггерного блока, триггерного блока базы данных, блока метода класса, блока конструктора класса, или блока свойств доступа. После чего возвращает управление вызывающей процедуре, определенной пользователем функции, методу, конструктору, или свойству доступа. Если же не существует вызывающей программы, то RETURN возвращает управление инструменту, который вызвал процедуру. Далее приведен синтаксис для оператора RETURN:
RETURN
[ return-value |
ERROR [ return-value | error-object-expression ] |
NO-APPLY ]
Здесь,
return-value, это значение, которое RETURN возвращает вызывающей программе с, или без, состояния ERROR.
ERROR, Вызывает состояние ERROR в вызывающем блоке. Может вызвать состояние ERROR для следующих операторов в вызывающей программе:
  • Оператор RUN для процедуры;
  • Любой оператор, который вызывает метод класса;
  • Любой оператор, который вызывает функцию NEW или DYNAMIC-NEW, чтобы создать экземпляр класса (вызывает конкретный конструктор и все другие конструкторы из иерархии класса);
  • Любой оператор, который обращается к свойству, определенному средствами доступа к свойству.
Вы можете использовать опцию ERROR в процедуре, триггерном блоке базы данных, основанном на методе класса, конструкторе, методе средств доступа к свойству. Однако чтобы поднять ошибку за пределами триггерного блока, вы не можете использовать опцию ERROR в триггерном блоке пользовательского интерфейса или в деструкторе. Любые значения, которые установлены для параметров OUTPUT или INPUT-OUTPUT перед RETURN ERROR, выполнятся, и не будут возвращены в вызывающую программу.
Следующая таблица показывает, как обращаться к return-value в вызывающей программе в различных случаях: 

Ситуация

Как получить доступ

return-value определен без опции ERROR в процедурном или триггерном блоке

Доступ осуществляется с помощью функции RETURN-VALUE.

return-value определен для метода non-VOID или для пользовательской функции без опции ERROR

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

return-value определен с опцией ERROR

Доступ с помощью функции RETURN-VALUE. Для структурного обработчика ошибок, вы так же можете получить доступ через свойство ReturnValue объекта ошибки (error object)

 

error-object-expression , это свойство документировано в части “Использование классов ABL Error”

NO-APPLY, подавляет стандартное поведение для текущего события пользовательского интерфейса. Вы можете использовать эту опцию в триггерном блоке пользовательского интерфейса. Например, по умолчанию, при нажатии клавиши в fill-in поле, в нем должен отобразиться символ. Если вы воспользуетесь RETURN NO-APPLY в триггере, этого не произойдет и NO-APPLY вернет без установки return-value.

 

Особенности RETURN для пользовательских функций

Пользовательские функции, которые определяются оператором FUNCTION, возвращают значения определенного типа данных. Оператор RETURN это инструмент, который используется в теле функции для возврата её значения. Этот факт лишает возможности использовать оператор RETURN ERROR так же, как он используется в других блоках.

RETURN ERROR в пользовательской функции не поднимает ошибку в вызывающей программе. Вместо этого, он устанавливает переменную функции в неопределенное значение. Поэтому, Вы можете использовать его для определения наличия ошибки, проверяя неопределенное значение в итоговой переменной после вызова функции. Это работает только, если функция использует оператор RETURN ERROR, и у итоговой переменной есть заранее определенное значение перед выполнением функции.

Пример:

DEFINE VARIABLE iFuncReturn AS INTEGER INITIAL 99 NO-UNDO.
FUNCTION ErrorTest RETURNS INTEGER:
RETURN ERROR.
END FUNCTION.
ASSIGN iFuncReturn = ErrorTest().
IF iFuncReturn EQ ? THEN
DISPLAY "Error in user-defined function.".

После запуска этого кода, вы получите:

Error in user-defined function.




Главная |  Статьи |  Книги |  Гостевая |  Ссылки |  От автора |  Download ProKb


������ ᠩ� pr Online ProKB Blogger Welcome to Russian Progress Users Group at Facebook Welcome to Russian Progress Users Group at LinkedIn
© 2009 - 2011 Все права на материалы, находящиеся на сайте www.openedge.ru, охраняются в соответствии с законодательством РФ, в том числе, об авторском праве и смежных правах.
При любом использовании материалов сайта ссылка на источник обязательна.