BlockManager.java

/*
** Module   : BlockManager.java
** Abstract : common "scaffolding" for executing Progress-compatible code blocks
**
** Copyright (c) 2008-2025, Golden Code Development Corporation.
**
** -#- -I- --Date-- --JPRM-- ----------------------------------Description-----------------------------------
** 001 GES 20080509   @38517 Created initial version. Implements the core
**                           "scaffolding" for executing 4GL-compatible
**                           code blocks. The API is designed to handle
**                           all possible block constructs and for the
**                           converted code to delegate the execution of
**                           those code blocks to this class. This greatly
**                           reduces the amount of code in the converted
**                           business logic.
** 002 GES 20080619   @38884 Now provides more detailed block types to the
**                           transaction manager. ON ENDKEY UNDO, RETRY is
**                           now signalled to the TM as well.
** 003 GES 20080625   @38958 Shifted the TM to the BlockType enum and
**                           moved the enum to be a separate class.
** 004 GES 20080701   @39058 FOR blocks/loops must honor user-defined
**                           ENDKEY behavior in preference to the default
**                           behavior for a query "off end".
** 005 GES 20080818   @39433 Added some UNDO stmt signatures. Fix to add
**                           the error prop to DO blocks/loops that are
**                           full transactions (it is implicit).
** 006 GES 20080822   @39519 Added missing function for GO-ON editing
**                           blocks, implicit ERROR property support for
**                           DO blocks/loops that are marked as FULL
**                           transaction types AND ILP support to convert
**                           NEXT to LEAVE.
** 007 GES 20080829   @39694 Added honorStop() support.
** 008 GES 20080924   @39934 Fix for QueryOffEndException processing.
**                           It must always cause a FOR loop or block
**                           to UNDO, LEAVE.
** 009 SIY 20081003   @40016 Added notification of listeners about 
**                           conditions triggered in blocks to which they
**                           are bound.
** 010 GES 20081106   @40361 Editing blocks must handle an error generated
**                           by the END-ERROR key by re-throwing it (just
**                           as is done in the UPDATE stmt). This needs
**                           to be done for all forms of editing block,
**                           not just one with the UPDATE stmt.
** 011 SIY 20081111   @40412 Added UNKNOWN Condition type, changed 
**                           visibility of exceptionToCondition, other 
**                           minor cleanups.
** 012 GES 20081126   @40740 Fixes for interactions counter and END-ERROR
**                           processing in EDITING and DO blocks/loops.
** 013 GES 20090115   @41132 Fix for loophole in condition processing.
**                           If processCondition() is about to re-throw
**                           an exception, it must trigger abnormalEnd()
**                           processing first.
** 014 SVL 20090415   @41799 Fixed error handing for editing blocks.
** 015 GES 20090512   @42148 Added execution statistics support.
** 016 CA  20090727   @43396 When a query associated or nested with a FOR 
**                           or FOR EACH block goes off end, its 
**                           associated buffers must not process the 
**                           undoables (the buffer must not reference any 
**                           record after the UNDO, LEAVE).
** 017 GES 20090729   @43443 Added validation processing hooks at the end of
**                           every block or loop, just before normal exit or
**                           iteration.
** 018 CA  20090731   @43471 Fixed query off-end processing. When the query 
**                           for a FOR or FOR EACH block finds no more records,
**                           the loop must be allowed to finish, by performing
**                           the implicit END-KEY action (UNDO, LEAVE), even
**                           if the user has defined an explicit END-KEY 
**                           action. For END-KEY conditions generated by a FIND
**                           statement, the block must execute the default
**                           END-KEY action if no explicit one is defined. 
**                           Else, it must execute the user-defined action.
** 019 CA  20090804   @43505 Fixed undo, leave when used inside a FOR block. 
**                           Cleanup TM related static imports. Fixed PRESELECT
**                           query in DO/REPEAT blocks - the record buffers 
**                           associated with the query must not reference any 
**                           record until a FIND statement is executed on the 
**                           buffer.
** 020 ECF 20090816   @43656 Fixed output parameter support for database
**                           fields. Modified topLevelBlock() and
**                           functionBlock() to call out to the current
**                           block's OutputParameterAssigner, if any, to copy
**                           output parameters' values back to the database
**                           fields with which they are associated.
** 021 GES 20090831   @43801 Don't raise ERROR in caller if the called code is a function.
** 022 CA  20130123          Pass the Block instance to pushScope, so it will be saved by the
**                           BlockDefinition. Added APIs to support functions returning rowid,
**                           recid and int64 values.   
** 023 CA  20130129          Added "function returns longchar" support.
** 024 CA  20130209          Added support for functions returning extent.  Refactored the 
**                           function call APIs to use generics.
** 025 CA  20130315          Added returnNormal(WrappedResource) API, to be used when the HANDLE
**                           attribute is used by this statement (in this case, HANDLE returns a
**                           WrappedResource and not a real handle).
** 025 OM  20130329          Added returnNormal (long val) since decimal variant loses precision.
**                           Fixed return type in functionBlock() by applying "conversion"
**                           constructor if needed.
** 026 CA  20131116          Fixed pushing of the TARGET- and SOURCE-PROCEDURE for java-style
**                           function calls.
** 027 CA  20140218          Resolved PROGRAM-NAME in case of java-style function calls: push to
**                           a dedicated stack the closest function name, before invoking the 
**                           function's body.
** 028 HC  20140708          Added support for error handling of the extent parameter wrapper 
**                           classes (AbstractExtentParameter). 
** 029 SVL 20140709          Handle InvalidParameterConditionException in topLevelBlock.
** 030 ECF 20140813          Added processValidateWorker to preserve and restore certain work area
**                           state which would otherwise be corrupted by database write triggers
**                           being fired during validation processing.
** 031 VIG 20140709          Added ConditionException processing for _MSG function to 
**                           the processBody method.
** 032 GES 20141014          Added Block.fini() call support. It must be called every time the
**                           body() is actually executed (no matter whether on the first
**                           execution, an iteration, a retry or when the body is exiting
**                           normally or abnormally.  In all cases there is a 1 to 1 association
**                           of block body execution to fini method execution. This matches the
**                           4GL FINALLY block feature.
** 033 GES 20150204          Clear GO-PENDING when a NEXT statement is used in an EDITING block.
** 034 CA  20150222          An EDITING block is a no-op if no widgets are specified (i.e. all 
**                           WHEN clauses are false).
** 036 OM  20150709          Added support for error conditions in OutputParameterAssigner.
** 037 CA  20150813          Improve performance of user-def function calls converted to java 
**                           method calls: the legacy function name is passed at the function 
**                           definition, to the function* emitted API.  If this is set, this will
**                           avoid calling the expensive ProcedureManager.resolveClosestMethod.
** 038 ECF 20150815          Implemented more efficient reflection logic in functionBlock.
** 039 ECF 20160206          Pass exceptional cause of certain rollback operations to TM.
** 040 GES 20160518          Major rewrite to implement lambda expressions.
** 041 OM  20160906          Small optimization.
** 042 GES 20160830          Added support for Block.pre() to replace use of the default c'tor.
**         20160907          Modified how the containing business logic instance is obtained for
**                           an external procedure. When lambdas are used, this instance MUST be
**                           passed through as a parameter to the externalProc() call.
** 043 CA  20180521          Added stopAfter stubs for DO's STOP-AFTER option.
**     CA  20180528          Added UNLESS-HIDDEN to the UPDATE/SET/PROMPT-FOR ... EDITING blocks.
** 044 CA  20181216          Added ON ... THROW support and BLOCK-LEVEL and ROUTINE-LEVEL stmts.
**                           Added stub for UNDO, THROW.
**                           Added stub for CATCH statement.
** 045 CA  20190122          internalProcedure calls emitted for constructor or destructor methods
**                           defined for a legacy 4GL class must specify the caller name and 
**                           either the instance or .class, to allow Java direct class.
**     CA  20190219          Added runtime for ROUTINE-LEVEL ON ERROR UNDO,THROW and 
**                           BLOCK-LEVEL ON ERROR UNDO,THROW.
**                           Basic runtime for legacy error management.
**     GES 20190323          Reduced context local lookups.
**     CA  20190324          Improved the statistics to record the execution time.
**                           returnWorker now avoids building a Java array for all calls.
**     GES 20190324          Implemented TransactionHelper instead of direct usage of the static
**                           TM API.  This allows the elimination of context local usage in TM.
**     CA  20190325          Implemented ProcedureHelper and ControlFlowOpsHelper instead of 
**                           direct usage of the static API.
** 046 CA  20190628          Track if an AppError is from a RETURN ERROR statement.
** 047 HC  20190701          Fixed returnError to allow raising any legacy error type. Added
**                           marking of a returned object as 'pending-assign' to prevent deletion
**                           of the object before is is returned to the caller.
** 048 CA  20190710          Added API to get the return value from a function (if it applies).
**     CA  20190720          Always load a legacy class, if a static method is accessed.
** 049 AIL 20190917          Added the ValidationUnwindException handling inside the blocks.
**         20191119          Replaced ValidationUnwindException with default on error throw
**     CA  20191119          Track the executing legacy class, to be able to register any buffer  
**                           to its source definition class.
**     GES 20191122          Added processCatch().
** 050 CA  20200122          Javadoc fixes.
**     CA  20200312          Fixes for UNDO, THROW and RETURN ERROR, in case when a OO-like 
**                           error condition needs to be generated.
**     CA  20200324          More fixes related to OO-like error processing via AppError.
**     CA  20200330          More fixes related to OE-compatible error management, in constructor 
**                           case and 'implicit' 4GL ERROR conditions.
**     CA  20200407          ERROR conditions generated by the FWD runtime must be deferred, so
**                           that they can be emitted by the client-side, too.
**     CA  20200427          Replaced isValid().booleanValue() calls with _isValid().
**     CA  20200528          undoThrowTopLevel must mark the AppError as 'from return', to be able to use the 
**                           return value message.
** 051 CA  20200713          Fixed 'RETURN ?' in a procedure - the RETURN-VALUE must be set to unknown.
**     GES 20200731          Eliminated context-local lookups by using ErrorHelper.
** 052 CA  20200927          Use WorkArea.cfops.setReturnValue(String) instead of direct ControlFlowOps call.
**     CA  20200927          Avoid context-local lookups by relying on the helper instance.
**     CA  20210216          Arithmetic operations are always int64 - this requires special processing when 
**                           passing such an expression as an argument, so the conversion-time type of the 
**                           expression is preserved.  If the assignment of the argument fails, the top-level
**                           must not be invoked.
**     CA  20210310          Small performance improvement (avoid unnecessary setup if the block doesn't have
**                           a fini method).
**     SVL 20210316          Fixed RETURN NO-APPLY for persistent triggers.
**     CA  20210428          A memptr returned by a function call must be the real reference, as a SET-SIZE
**                           called on a OO property will change that property directly.
**     CA  20210428          For function/OO calls passed as an argument to another call, evaluate them via a 
**                           lambda expression so that the 'output parameter assigner' is not corrupted.
**     HC  20210511          Fixed widget display validation on GO event in EDITING block and
**                           WAIT-FOR.
**     CA  20210609          Reworked INPUT/INPUT-OUTPUT parameters to a new approach, where they are explicitly 
**                           initialized at the method's execution, and not at the caller's arguments.
**                           (backed out CA/20210428).
**     GES 20210809          Fixed FINALLY block to execute after commitables/finalizables are processed.
**     OM  20211111          Added transaction support for FINALLY blocks.
**     CA  20211112          Fixed RETURN-ERROR when this is done in the root procedure for a remote appserver 
**                           call (the error condition must be propagated to the remote side).
**     OM  20211201          Improved transaction support for finally blocks.
**     OM  20211130          Allow function return value to be overriden.
**     CA  20220120          Performance improvement for pushing a new calee scope, keep the already resolved
**                           internal entry legacy name.
**     CA  20220120          When a legacy OO exception is consumed, release it so it can be deleted.
**     CA  20220128          All non-empty messages in a thrown legacy error must be displayed, if the error 
**                           is not processed by a CATCH block. 
**     CA  20220208          Only RETURN ERROR can raise legacy OO errors on the caller's side for appserver 
**                           calls.
**     CA  20220304          An ERROR condition being raised from within a block which can catch SysError must
**                           be morphed into a legacy SysError exception, and not raise an ERROR condition.
**     VVT 20220305          NPE in hasLegacyError fixed when method is called from JUnit.
**     AL2 20220314          Poly functions shouldn't explicitly convert the return value.
**                           Wrap return value in proxies to honor dynamic function behavior.
**     CA  20220426          CATCH block can be nested, added a 'catchBlock' stub which will have the runtime
**                           support for a CATCH block's default block.
**     CA  20220531          Fixed propagation of explicit legacy exceptions - they must propagate if the 
**                           block has ON ERROR UNDO, THROW or if they are explicitly throw by the application.
**     CA  20220606          Added lazy loading of legacy converted classes.
**     TW  20220803          Error-status:error must be set for return error in method, while return error
**                           in old-style ABL function must remain the same. Refs: #6567.
**     TW  20220804          Harden against NPE.
**     TW  20220817          Error-status:error must be set for return error in static method.
**     CA  20220930          Added a helper to expose the context-local 'markPendingDynCall' API.
**     CA  20220901          Refactored scope notification support: ScopeableFactory was removed, and the 
**                           registration is now specific to each type of scopeable.  For each case, the block
**                           will be registered for scope support (for that particular scopeable) only when
**                           the scopeable is 'active' (i.e. unnamed streams or accumulators are used).  This
**                           allows a lazy registration of scopeables, to avoid the unnecessary overhead of
**                           processing all the scopeables for each and every block.
**     EVL 20221017          Fix from CA to protect from client silent abend for LegacyErrorException.
**     TJD 20220504          Java 11 compatibility minor changes
**     CA  20221123          If an 'object' instance is assigned in the FINALLY block and also referenced by 
**                           the RETURN statement, then do not remove it from 'pendingAssign'.
**     CA  20220613          Allow OO exceptions to propagate to the remote side, when exiting the root block 
**                           on a appserver call.
**     CA  20230116          Improvement from context-local state resolution.
** 053 GES 20230116          Avoid throw/catch for normal return in a function (performance optimization).
**                           Added variants of returnNormal/returnExtentNormal called storeReturnValue/
**                           storeExtentReturnValue to make the code read better (they are really the same
**                           code at this point in time).
** 054 CA  20230307          For p2j.oo code, for now let returnNormal throw a ReturnUnwindException, as this
**                           code is not refactored to use the GES/20230116 approach.
** 055 CA  20230313          A missed case for CA/20230307 - check static OO method calls, too, as the static
**                           classes have a different registry in ObjectOps.
** 056 GBB 20230322          Log legacy error before throwing.
** 057 RAA 20230525          Creating a new BaseDataType instance is now done using BaseDataTypeFactory.
** 058 OM  20230505          Avoided incorrect INDEX_OUT_OF_RANGE exception.
** 059 CA  20230609          If a structured exception reaches a block with an ON ERROR clause with an action
**                           something other than THROW, it will consume this legacy exception and treat it as
**                           an ERROR condition.
**     CA  20230615          The UNDO, THROW executed from a CATCH block must target the parent block of the
**                           block where the CATCH was defined.  Also, the CATCH block must execute just 
**                           before the FINALLY block, in TM.popScope.
**                           Small optimization - avoid using obj.ref() and use instead obj.ref, if the 'obj' 
**                           instance is known to be valid.
** 060 CA  202300707         A RETURN in a CATCH block associated with a top-level block will emit via 
**                           'storeReturnValue'; identify this call and treated as if it was from the top-level
**                           block. 
**                           Also, clear any pending errors before the CATCH is executed.
** 061 CA  20230713          Fixed a regression in H059 and H060 - a RETURN from a CATCH block was leaking to 
**                           previous block and terminating it.
**                           Other optimizations related to 'storeReturnValue' and basic processing of the
**                           CATCH and FINALLY termination blocks.
** 062 AL2 20230801          Refactored looping blocks to allow query parameter.
** 063 ME  20230919          Wrap return value from functionBlock if return type is BaseDataType (invoke, poly).
** 064 OM  20230921          Added static method trigger().
** 065 CA  20231009          Fixed the 'executing' type for direct Java calls.
** 066 CA  20230919          Fixed a bug for direct Java call, the 'executing' type was not computed correctly. 
** 067 CA  20230802          Ensure the OutputParameterAssigner gets reset if a legacy OO exception is thrown
**                           in the FINALLY or CATCH block.
** 068 CA  20231026          An object instance being returned must be tracked on the caller block, as the
**                           returned value may or may not be assigned, and the callee may return a freshly
**                           created instance which will never gets discarded if is never assigned again.
**                           Do not pin the Block instance to BlockDefinition, as it is never read.
** 068 CA  20231129          Use method references where possible.
**     CA  20231216          'checkFunctionReturn' needs to process only the top of stack, as this is where
**                           current return value can ever exist. 
**     CA  20231221          ObjectOps scopeable support is registered only when: a var is defined, a new 
**                           instance is being created, or a function/method returns 'object'.
** 069 AL2 20230801          Refactored looping blocks to allow query parameter.
** 070 ES  20231203          Added a new parameter for forBlock to allow multiple query directions.
**     ES  20231212          Removed casting to CompundQuery in forEachWorker and forWorker.
**     ES  20231213          Adding a switch in forBlockWorker to select operation performed on the query parameter.
** 071 AL2 20240221          Process the legacy exceptions to trigger rollbacks of the block it passes through.
** 072 SVL 20240207          Preserve case sensitivity of the returned character value of a function.
** 073 AL2 20240308          Rollback on legacy error exceptions only when a (sub-)transaction is active. 
**                           Don't let error condition exceptions enter abnormal handling with ON ... THROW.
** 074 AL2 20240229          Avoid roll-back on off-end query that was used for the for-each or for-block.
**         20240311          Restore the processOffEndListeners calls; they are used to reset the off-end.
** 075 AL2 20240310          Validate at the end of a loop iteration even if not inside a transaction.
** 076 CA  20240324          Use logical constants for TRUE, FALSE, UNKNOWN, within internal FWD runtime.
** 077 ES  20240404          Set iteration flag for the query defined in FOR EACH block.
** 078 SC  20240516          Added a check for dynamic call in functionBlock and created a proxy if the 
**                           function return type is different from the returned value type         
** 079 SB  20240523          Prevent rollback on legacy exception errors if there is a pending rollback.
**                           Refs #8728.
** 080 CA  20240522          Ensure 'abort' is called for OutputParameterAssigner in case of errors during
**                           pop scope processing (which includes catch/finally blocks).
** 081 DDF 20240523          Re-throw processed legacy error based on the reThrow flag of the error if possible.
**     DDF 20240524          Revert re-throw change and avoid NPE when matching condition is null.
** 082 CA  20240529          Fixed SC/078 when there is direct java calls.
** 083 CA  20240609          Once a structured exception is re-thrown, mark it as explicit, so it can be 
**                           re-thrown via top-level blocks.
** 084 ES  20240513          Added support for stop-after statement for Progress blocks.
**                           After each successful iteration of the block body the timer of the current block should
**                           be cleaned.
**                           Targeting the block for which stop-after timeout was raised.
**                           If a inner block of a targeted by a stop-after block has an ON STOP, RETRY, then the
**                           retry should be honored.
**         20240531          Added support to disable stop-after runtime with a parameter in directory.
**         20240604          Lazy initialization of the stopAfterTimer in WorkArea.
** 085 CA  20240708          A block needs to be aware if a RETURN ERROR or UNDO, THROW was used for exit, 
**                           as this will make a FINALLY block to act as if it executes in silent mode. Also,
**                           a CATCH block will not be executed when RETURN ERROR or UNDO, THROW is used.
** 086 AS  20240730          Moved exitTopLevel to finally block in topLevelBlock
** 087 AS  20240911          Fixed error propagation for errors thrown in caller.
** 088 TJD 20240314          BufferManager should be pending scopeable for editing block, fix by CA
**     TJD 20240409          Reset queryOffEnd listeners on beginning of foreach worker
** 089 ES  20240919          Prevent second rollback in case of an undoThrowTopLevel.
** 090 CA  20240625          Certain database-level ERROR conditions (like 132/buffer already exists with) 
**                           must be processed as if BLOCK-LEVEL ON ERROR UNDO, THROW is set (in other words,
**                           it can get morphed into a strcutured exceptions).
** 091 AS  20241204          In LOG-MANAGER context, log the numbered errors thrown by undoThrow. 
** 092 ES  20240115          In case the unnamed stream is redirected in the editiongBlock, call the 
**                           subsequent GenericFrame method (set, update or promtFor).
** 093 RNC 20250204          If the FOR-EACH query raises an error, leave the block instead of retrying.
** 094 CA  20250131          Added support for ON QUIT, {LEAVE|NEXT|...} - this must not rollback, but commit.
** 095 SP  20250210          Added storeReturnValue(Stream) and returnNormal(Stream) variants.
** 096 GBB 20250218          ErrorManager.displayError() calls moved to a new method displayErrorMessage, 
**                           where the legacy error is marked as displayed to avoid a second display.
**                           Duplicated code refactored.
** 097 ES  20250217          Added support for nested catch blocks.
** 098 ES  20250227          Added runtime support for undo, throw with Progress.Lang.Stop error. Added methods
**                           undoThrowStopTopLevel and undoThrowStop.
**     ES  20250228          Added runtime supoort for UNDO, RETURN ERROR exe statement.
*/

/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
** 
** Additional terms under GNU Affero GPL version 3 section 7:
** 
**   Under Section 7 of the GNU Affero GPL version 3, the following additional
**   terms apply to the works covered under the License.  These additional terms
**   are non-permissive additional terms allowed under Section 7 of the GNU
**   Affero GPL version 3 and may not be removed by you.
** 
**   0. Attribution Requirement.
** 
**     You must preserve all legal notices or author attributions in the covered
**     work or Appropriate Legal Notices displayed by works containing the covered
**     work.  You may not remove from the covered work any author or developer
**     credit already included within the covered work.
** 
**   1. No License To Use Trademarks.
** 
**     This license does not grant any license or rights to use the trademarks
**     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
**     of Golden Code Development Corporation. You are not authorized to use the
**     name Golden Code, FWD, or the names of any author or contributor, for
**     publicity purposes without written authorization.
** 
**   2. No Misrepresentation of Affiliation.
** 
**     You may not represent yourself as Golden Code Development Corporation or FWD.
** 
**     You may not represent yourself for publicity purposes as associated with
**     Golden Code Development Corporation, FWD, or any author or contributor to
**     the covered work, without written authorization.
** 
**   3. No Misrepresentation of Source or Origin.
** 
**     You may not represent the covered work as solely your work.  All modified
**     versions of the covered work must be marked in a reasonable way to make it
**     clear that the modified work is not originating from Golden Code Development
**     Corporation or FWD.  All modified versions must contain the notices of
**     attribution required in this license.
*/

package com.goldencode.p2j.util;

import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.function.*;
import java.util.logging.Level;
import java.io.*;
import java.lang.reflect.*;

import com.goldencode.p2j.directory.*;
import com.goldencode.p2j.main.*;
import com.goldencode.p2j.net.Control;
import com.goldencode.p2j.oo.lang.*;
import com.goldencode.p2j.persist.*;
import com.goldencode.p2j.security.ContextLocal;
import com.goldencode.p2j.security.RestrictedUseException;
// the following are dependencies on the UI package which we would prefer to
// eliminate if the services can be cleanly abstracted without making the
// calling code worse from a readability perspective
import com.goldencode.p2j.ui.LogicalTerminal;
import com.goldencode.p2j.util.ProcedureManager.ProcedureHelper;
import com.goldencode.p2j.util.logging.CentralLogger;
import com.goldencode.p2j.ui.CommonFrame;
import com.goldencode.p2j.ui.FrameElement;
import com.goldencode.p2j.ui.GenericFrame;
import com.goldencode.p2j.ui.EventList;
import com.goldencode.p2j.security.SecurityManager;
import com.goldencode.util.*;

import static com.goldencode.p2j.util.TransactionManager.*;

/**
 * Provides an external API that allows the Progress-compatible code block
 * semantics to be provided with a minimum of code in the caller. This class
 * encodes the "scaffolding" necessary to properly process code blocks with
 * the right behavior.  The external interface is designed to be statically
 * imported to make access simple, short and easy to read. The API has been
 * designed to minimize name conflicts.  The scaffolding code uses the
 * {@link TransactionManager} extensively to implement the proper behavior.
 */
public class BlockManager
{
   /** Logger */
   private static final CentralLogger LOG = CentralLogger.get(BlockManager.class.getName());
   
   /** Stores context-local state variables. */
   private static final ContextContainer work = new ContextContainer();
   
   /** Encodes the possible levels of transaction support for each block. */
   public static enum TransactionType { NONE, SUB, FULL };
   
   /** Encodes the possible condition types. */
   public static enum Condition { ERROR, ENDKEY, STOP, QUIT, QUIT_COMMIT, UNKNOWN };
   
   /** Encodes the possible actions in response to given conditions. */
   public static enum Action
   {
      LEAVE,
      NEXT, 
      RETRY, 
      RETURN_NORMAL,
      RETURN_CONSUME,
      RETURN_ERROR,
      THROW
   }
   
   /** The fixed label of all FINALLY: blocks. */
   public static final String FINALLY_BLOCK_LABEL = "__finally__";
   
   /** The fixed label of all CATCH: blocks. */
   public static final String CATCH_BLOCK_LABEL = "__catch__";
   
   /** Encodes the possible types of return statement. */
   enum ReturnType { NORMAL, CONSUME, ERROR, STORE }
   
   /** Encodes the possible responses to a flow control event. */
   private static enum Disposition { BREAK, CONTINUE, THROW, NONE };
   
   /** Directory entry to define an execution statistics output file. */
   private static final String STATS_FILE = "block-execution-statistics";
   
   /** Synthetic null value to use in a deque which doesn't accept null values. */
   private static final Object NULL = new Object();
   
   /** Output filename in which to write execution statistics. */
   private static String statsFile = null;
   
   /** Stores calls execution statistics. */
   private static Map<String, AtomicInteger> stats = null;

   /** Stores timing execution statistics. */
   private static Map<String, AtomicLong> times = null;
   
   static
   {
      Directory dir = DirectoryManager.getInstance();
      statsFile = dir.getString(Directory.ID_RELATIVE, STATS_FILE, null);
      
      if (statsFile != null)
      {
         stats = new ConcurrentHashMap<String, AtomicInteger>();
         times = new ConcurrentHashMap<String, AtomicLong>();
         StandardServer.register(new StatsHelper());
      }
   }
   
   /**
    * API for ROUTINE-LEVEL ON ERROR UNDO,THROW statement.
    * <p>
    * This will change the default ON ERROR from UNDO, RETRY to UNDO, THROW for all routines 
    * in this procedure or class (including its 'execute' method).
    * <p>
    * This includes:
    * <ul>
    *    <li>external program</li>
    *    <li>internal procedures</li>
    *    <li>functions </li>
    *    <li>user-defined functions</li>
    *    <li>class methods</li>
    *    <li>class constructors (but not destructors) - including static</li>
    *    <li>class property getter/setter - including static</li>
    *    <li>schema trigger programs - including static</li>
    * </ul>
    * TODO: does this affect super-classes, in case of OO instances?
    * 
    * @param    condition
    *           ERROR.
    * @param    action
    *           THROW.
    */
   public static void onRoutineLevel(Condition condition, Action action)
   {
      // TODO: the condition/action currently is not propagated or saved - ERROR, THROW is always assumed
      work.get().pm.markRoutineLevelUndoThrow();
   }
   
   /**
    * API for BLOCK-LEVEL ON ERROR UNDO,THROW statement.
    * <p>
    * This will change the default ON ERROR from UNDO, RETRY to UNDO, THROW for all routines 
    * in this procedure or class (including its 'execute' method).
    * <p>
    * This includes:
    * <ul>
    *    <li>external program</li>
    *    <li>internal procedures</li>
    *    <li>functions </li>
    *    <li>user-defined functions</li>
    *    <li>class methods</li>
    *    <li>class constructors (but not destructors) - including static</li>
    *    <li>class property getter/setter - including static</li>
    *    <li>schema trigger programs - including static</li>
    *    <li>REPEAT, FOR, DO TRANSACTION blocks</li>
    * </ul>
    * TODO: does this affect super-classes, in case of OO instances?
    * 
    * @param    condition
    *           ERROR.
    * @param    action
    *           THROW.
    */
   public static void onBlockLevel(Condition condition, Action action)
   {
      // TODO: the condition/action currently is not propagated or saved - ERROR, THROW is always
      // assumed
      work.get().pm.markBlockLevelUndoThrow();
   }
   
   /**
    * Offers runtime support for stop-after statement for Progress blocks.
    * 
    * @param    val
    *           The number of seconds to wait before raising a QUIT.
    */
   public static void stopAfter(NumberType val)
   {
      stopAfter(val.longValue());
   }
   
   /**
    * Offers runtime support for stop-after statement for Progress blocks.
    * 
    * @param    val
    *           The number of seconds to wait before raising a QUIT.
    */
   public static void stopAfter(long val)
   {
       WorkArea wa = work.get();
       
       if (!wa.isStopAfterActive || val == 0)
       {
          return;
       }
       
       if (wa.stopAfterTimer == null)
       {
          try 
          {          
             Control control = SecurityManager.getCurrentContextControl();
             String threadName = Thread.currentThread().getName();
             wa.stopAfterTimer = new StopAfterTimer(threadName, control);
             wa.errHelper.setStopAfterTimer(wa.stopAfterTimer);
             wa.tm.registerStopAfterTimer(wa.stopAfterTimer);
          }
          catch (RestrictedUseException e)
          {
             LOG.log(Level.WARNING,
                   "Restricted use of Control.getCurrentContextControl()",
                   e);
             return;
          }
       }

       StopAfterTimer stopAfterTimer = wa.stopAfterTimer;
       BlockDefinition block = wa.tm.getBlock();
          
       if (stopAfterTimer.isBlockRegistered(block))
       {
          return;
       }
          
       StopAfterTimer.Task task = stopAfterTimer.addTimeOut(block, val);
       wa.tm.registerFinalizable(task, false);
   }
   
   /**
    * Execute the given external procedure block with a default transaction level of
    * <code>TransactionType.SUB</code>.
    * <p>
    * This form may only be used with block instances that are anonymous inner classes since
    * the containing business logic class can be calculated using reflection. Any usage with
    * lambdas will fail!
    *
    * @param    block
    *           The code to execute.
    */
   public static void externalProcedure(Block block)
   {
      externalProcedure(null, null, TransactionType.SUB, block);
   }
   
   /**
    * Execute the given external procedure block with the given transaction level.
    * <p>
    * This form may only be used with block instances that are anonymous inner classes since
    * the containing business logic class can be calculated using reflection. Any usage with
    * lambdas will fail!
    *
    * @param    lvl
    *           The transaction level for the given block.
    * @param    block
    *           The code to execute.
    */
   public static void externalProcedure(TransactionType lvl, Block block)
   {
      externalProcedure(null, null, lvl, block);
   }
   
   /**
    * Execute the given external procedure block with a default transaction level of
    * <code>TransactionType.SUB</code>.
    * <p>
    * This form is suitable for use with lambdas but in such a case the <code>referent</code>
    * must be non-null.
    *
    * @param    referent
    *           The instance of the containing business logic class from which this is being
    *           called.  If this is non-null, then <code>block</code> can be an instance created
    *           using lambdas.  If <code>null</code>, then <code>block</code> MUST BE an
    *           anonymous inner class of the containing business logic instance so that instance
    *           can be calculated via reflection.
    * @param    block
    *           The code to execute.
    */
   public static void externalProcedure(Object referent, Block block)
   {
      externalProcedure(referent, TransactionType.SUB, block);
   }
   
   /**
    * Execute the given external procedure block with the given transaction level.
    * <p>
    * This form is suitable for use with lambdas but in such a case the <code>referent</code>
    * must be non-null.
    *
    * @param    referent
    *           The instance of the containing business logic class from which this is being
    *           called.  If this is non-null, then <code>block</code> can be an instance created
    *           using lambdas.  If <code>null</code>, then <code>block</code> MUST BE an
    *           anonymous inner class of the containing business logic instance so that instance
    *           can be calculated via reflection.
    * @param    lvl
    *           The transaction level for the given block.
    * @param    block
    *           The code to execute.
    */
   public static void externalProcedure(Object referent, TransactionType lvl, Block block)
   {
      // TODO: move this in a more performance-wise place (i.e. after user login and Agent.listen)
      
      // ensure certain context-local data has loaded
      ProcedureManager.load();

      topLevelBlock(null, referent, null, lvl, BlockType.EXTERNAL_PROC, block);
   }
   
   /**
    * Execute the given external procedure block with a default transaction level of
    * <code>TransactionType.SUB</code>.
    * <p>
    * This form is suitable for use with lambdas but in such a case the <code>referent</code>
    * must be non-null.
    *
    * @param    def
    *           The Java class associated with a legacy OE class, if this code is part of a legacy
    *           OE class; otherwise, <code>null</code>.
    * @param    referent
    *           The instance of the containing business logic class from which this is being
    *           called.  If this is non-null, then <code>block</code> can be an instance created
    *           using lambdas.  If <code>null</code>, then <code>block</code> MUST BE an
    *           anonymous inner class of the containing business logic instance so that instance
    *           can be calculated via reflection.
    * @param    block
    *           The code to execute.
    */
   public static void externalProcedure(Class<?> def,
                                        Object referent, 
                                        Block block)
   {
      externalProcedure(def, referent, TransactionType.SUB, block);
   }
   
   /**
    * Execute the given external procedure block with the given transaction level.
    * <p>
    * This form is suitable for use with lambdas but in such a case the <code>referent</code>
    * must be non-null.
    *
    * @param    def
    *           The Java class associated with a legacy OE class, if this code is part of a legacy
    *           OE class; otherwise, <code>null</code>.
    * @param    referent
    *           The instance of the containing business logic class from which this is being
    *           called.  If this is non-null, then <code>block</code> can be an instance created
    *           using lambdas.  If <code>null</code>, then <code>block</code> MUST BE an
    *           anonymous inner class of the containing business logic instance so that instance
    *           can be calculated via reflection.
    * @param    lvl
    *           The transaction level for the given block.
    * @param    block
    *           The code to execute.
    */
   public static void externalProcedure(Class<?> def, 
                                        Object referent, 
                                        TransactionType lvl, 
                                        Block block)
   {
      // TODO: move this in a more performance-wise place (i.e. after user login and Agent.listen)
      
      // ensure certain context-local data has loaded
      ProcedureManager.load();

      topLevelBlock(def, referent, null, lvl, BlockType.EXTERNAL_PROC, block);
   }
   
   /**
    * Execute the given internal procedure block with a default transaction
    * level of <code>TransactionType.SUB</code>.
    *
    * @param    block
    *           The code to execute.
    */
   public static void internalProcedure(Block block)
   {
      internalProcedure(TransactionType.SUB, block);
   }
   
   /**
    * Execute the given internal procedure block with the given transaction
    * level.
    *
    * @param    lvl
    *           The transaction level for the given block.
    * @param    block
    *           The code to execute.
    */
   public static void internalProcedure(TransactionType lvl, Block block)
   {
      topLevelBlock(null, null, null, lvl, BlockType.INTERNAL_PROC, block);
   }
   
   /**
    * Execute the given internal procedure block with a default transaction
    * level of <code>TransactionType.SUB</code>.
    *
    * @param    legacyName
    *           The legacy name associated with the function being invoked via a java-style call. 
    *           If is <code>null</code>, it will be resolved by 
    *           {@link ProcedureManager#resolveClosestMethod}.
    * @param    block
    *           The code to execute.
    */
   public static void internalProcedure(String legacyName, Block block)
   {
      internalProcedure(legacyName, TransactionType.SUB, block);
   }
   
   /**
    * Execute the given internal procedure block with the given transaction
    * level.
    *
    * @param    legacyName
    *           The legacy name associated with the function being invoked via a java-style call. 
    *           If is <code>null</code>, it will be resolved by 
    *           {@link ProcedureManager#resolveClosestMethod}.
    * @param    lvl
    *           The transaction level for the given block.
    * @param    block
    *           The code to execute.
    */
   public static void internalProcedure(String legacyName, TransactionType lvl, Block block)
   {
      topLevelBlock(null, null, legacyName, lvl, BlockType.INTERNAL_PROC, block);
   }
   
   /**
    * Execute the given internal procedure block with a default transaction
    * level of <code>TransactionType.SUB</code>.
    *
    * @param    referent
    *           The referent to which this method belongs.
    * @param    legacyName
    *           The legacy name associated with the function being invoked via a java-style call. 
    *           If is <code>null</code>, it will be resolved by 
    *           {@link ProcedureManager#resolveClosestMethod}.
    * @param    block
    *           The code to execute.
    */
   public static void internalProcedure(Object referent, String legacyName, Block block)
   {
      internalProcedure(referent, legacyName, TransactionType.SUB, block);
   }
   
   /**
    * Execute the given internal procedure block with the given transaction
    * level.
    *
    * @param    referent
    *           The referent to which this method belongs.
    * @param    legacyName
    *           The legacy name associated with the function being invoked via a java-style call. 
    *           If is <code>null</code>, it will be resolved by 
    *           {@link ProcedureManager#resolveClosestMethod}.
    * @param    lvl
    *           The transaction level for the given block.
    * @param    block
    *           The code to execute.
    */
   public static void internalProcedure(Object          referent, 
                                        String          legacyName, 
                                        TransactionType lvl, 
                                        Block           block)
   {
      topLevelBlock(null, referent, legacyName, lvl, BlockType.INTERNAL_PROC, block);
   }
   
   /**
    * Execute the given internal procedure block with a default transaction
    * level of <code>TransactionType.SUB</code>.
    *
    * @param    def
    *           The Java class associated with a legacy OE class, if this code is part of a legacy
    *           OE class; otherwise, <code>null</code>.
    * @param    referent
    *           The referent to which this method belongs.
    * @param    legacyName
    *           The legacy name associated with the function being invoked via a java-style call. 
    *           If is <code>null</code>, it will be resolved by 
    *           {@link ProcedureManager#resolveClosestMethod}.
    * @param    block
    *           The code to execute.
    */
   public static void internalProcedure(Class<?> def,
                                        Object referent, 
                                        String legacyName, 
                                        Block block)
   {
      internalProcedure(def, referent, legacyName, TransactionType.SUB, block);
   }
   
   /**
    * Execute the given internal procedure block with the given transaction
    * level.
    *
    * @param    def
    *           The Java class associated with a legacy OE class, if this code is part of a legacy
    *           OE class; otherwise, <code>null</code>.
    * @param    referent
    *           The referent to which this method belongs.
    * @param    legacyName
    *           The legacy name associated with the function being invoked via a java-style call. 
    *           If is <code>null</code>, it will be resolved by 
    *           {@link ProcedureManager#resolveClosestMethod}.
    * @param    lvl
    *           The transaction level for the given block.
    * @param    block
    *           The code to execute.
    */
   public static void internalProcedure(Class<?>        def,
                                        Object          referent, 
                                        String          legacyName, 
                                        TransactionType lvl, 
                                        Block           block)
   {
      topLevelBlock(def, referent, legacyName, lvl, BlockType.INTERNAL_PROC, block);
   }
   
   /**
    * Execute the given trigger block as a SUB-transaction.
    *
    * @param    block
    *           The code to execute.
    */
   public static void trigger(Block block)
   {
      // TODO: check if TransactionType.FULL is not the appropriate type
      topLevelBlock(null, null, null, TransactionType.SUB, BlockType.DATABASETRIGGER, block);
   }
   
   /**
    * Execute the given function block with a default transaction level of
    * <code>TransactionType.SUB</code>.
    * 
    * @param    cls
    *           The function's return type.
    * @param    block
    *           The code to execute.
    *
    * @return   The return value from the block (or its nested blocks) which
    *           is the <code>unknown value</code> by default or on error.
    */
   public static <T extends BaseDataType> T function(Class<T> cls, Block block)
   {
      return (T) function(cls, TransactionType.SUB, block);
   }
   
   /**
    * Execute the given function block with the given transaction level.
    *
    * @param    cls
    *           The function's return type.
    * @param    lvl
    *           The transaction level for the given block.
    * @param    block
    *           The code to execute.
    *
    * @return   The return value from the block (or its nested blocks) which
    *           is the <code>unknown value</code> by default or on error.
    */
   public static <T extends BaseDataType> T function(Class<T>        cls,
                                                     TransactionType lvl,
                                                     Block           block)
   {
      return ((T) functionBlock(null, null, null, lvl, block, cls, -1));
   }
   
   /**
    * Execute the given function block with a default transaction level of
    * <code>TransactionType.SUB</code>, which returns an extent value.
    *
    * @param    cls
    *           The function's return type.
    * @param    extent
    *           The function's return extent value.
    * @param    block
    *           The code to execute.
    *
    * @return   The return value from the block (or its nested blocks).
    */
   public static <T extends BaseDataType> T[] extentFunction(Class<T> cls,
                                                             int      extent,
                                                             Block    block)
   {
      return (T[]) extentFunction(cls, extent, TransactionType.SUB, block);
   }
   
   /**
    * Execute the given function block with the given transaction level, which returns an extent
    * value.
    *
    * @param    cls
    *           The function's return type.
    * @param    extent
    *           The function's return extent value.
    * @param    lvl
    *           The transaction level for the given block.
    * @param    block
    *           The code to execute.
    *
    * @return   The return value from the block (or its nested blocks).
    */
   public static <T extends BaseDataType> T[] extentFunction(Class<T>        cls,
                                                             int             extent,
                                                             TransactionType lvl,
                                                             Block           block)
   {
      return (T[]) functionBlock(null, null, null, lvl, block, cls, extent);
   }
   
   /**
    * Execute the given function block with a default transaction level of
    * <code>TransactionType.SUB</code>, which returns a dynamic extent value.
    *
    * @param    cls
    *           The function's return type.
    * @param    block
    *           The code to execute.
    *
    * @return   The return value from the block (or its nested blocks).
    */
   public static <T extends BaseDataType> T[] extentFunction(Class<T> cls,
                                                             Block    block)
   {
      return (T[]) extentFunction(cls, TransactionType.SUB, block);
   }
   
   /**
    * Execute the given function block with the given transaction level, which returns a 
    * dynamic extent value.
    *
    * @param    cls
    *           The function's return type.
    * @param    lvl
    *           The transaction level for the given block.
    * @param    block
    *           The code to execute.
    *
    * @return   The return value from the block (or its nested blocks).
    */
   public static <T extends BaseDataType> T[] extentFunction(Class<T>        cls,
                                                             TransactionType lvl,
                                                             Block           block)
   {
      return (T[]) functionBlock(null, null, null, lvl, block, cls, 0);
   }

   /**
    * Execute the given function block with a default transaction level of
    * <code>TransactionType.SUB</code>.
    * 
    * @param    legacyName
    *           The legacy name associated with the function being invoked via a java-style call. 
    *           If is <code>null</code>, it will be resolved by 
    *           {@link ProcedureManager#resolveClosestMethod}.
    * @param    cls
    *           The function's return type.
    * @param    block
    *           The code to execute.
    *
    * @return   The return value from the block (or its nested blocks) which
    *           is the <code>unknown value</code> by default or on error.
    */
   public static <T extends BaseDataType> T function(String legacyName, Class<T> cls, Block block)
   {
      return (T) function(legacyName, cls, TransactionType.SUB, block);
   }
   
   /**
    * Execute the given function block with the given transaction level.
    *
    * @param    legacyName
    *           The legacy name associated with the function being invoked via a java-style call. 
    *           If is <code>null</code>, it will be resolved by 
    *           {@link ProcedureManager#resolveClosestMethod}.
    * @param    cls
    *           The function's return type.
    * @param    lvl
    *           The transaction level for the given block.
    * @param    block
    *           The code to execute.
    *
    * @return   The return value from the block (or its nested blocks) which
    *           is the <code>unknown value</code> by default or on error.
    */
   public static <T extends BaseDataType> T function(String          legacyName,
                                                     Class<T>        cls,
                                                     TransactionType lvl,
                                                     Block           block)
   {
      return (T) functionBlock(null, null, legacyName, lvl, block, cls, -1);
   }

   /**
    * Execute the given function block with a default transaction level of
    * <code>TransactionType.SUB</code>.
    * 
    * @param    referent
    *           The referent to which this method belongs.
    * @param    legacyName
    *           The legacy name associated with the function being invoked via a java-style call. 
    *           If is <code>null</code>, it will be resolved by 
    *           {@link ProcedureManager#resolveClosestMethod}.
    * @param    cls
    *           The function's return type.
    * @param    block
    *           The code to execute.
    *
    * @return   The return value from the block (or its nested blocks) which
    *           is the <code>unknown value</code> by default or on error.
    */
   public static <T extends BaseDataType> T function(Object   referent, 
                                                     String   legacyName, 
                                                     Class<T> cls, 
                                                     Block    block)
   {
      return (T) function(referent, legacyName, cls, TransactionType.SUB, block);
   }
   
   /**
    * Execute the given function block with the given transaction level.
    *
    * @param    referent
    *           The referent to which this method belongs.
    * @param    legacyName
    *           The legacy name associated with the function being invoked via a java-style call. 
    *           If is <code>null</code>, it will be resolved by 
    *           {@link ProcedureManager#resolveClosestMethod}.
    * @param    cls
    *           The function's return type.
    * @param    lvl
    *           The transaction level for the given block.
    * @param    block
    *           The code to execute.
    *
    * @return   The return value from the block (or its nested blocks) which
    *           is the <code>unknown value</code> by default or on error.
    */
   public static <T extends BaseDataType> T function(Object          referent,
                                                     String          legacyName,
                                                     Class<T>        cls,
                                                     TransactionType lvl,
                                                     Block           block)
   {
      return (T) functionBlock(null, referent, legacyName, lvl, block, cls, -1);
   }

   /**
    * Execute the given function block with a default transaction level of
    * <code>TransactionType.SUB</code>.
    * 
    * @param    def
    *           The Java class associated with a legacy OE class, if this code is part of a legacy
    *           OE class; otherwise, <code>null</code>.
    * @param    referent
    *           The referent to which this method belongs.
    * @param    legacyName
    *           The legacy name associated with the function being invoked via a java-style call. 
    *           If is <code>null</code>, it will be resolved by 
    *           {@link ProcedureManager#resolveClosestMethod}.
    * @param    cls
    *           The function's return type.
    * @param    block
    *           The code to execute.
    *
    * @return   The return value from the block (or its nested blocks) which
    *           is the <code>unknown value</code> by default or on error.
    */
   public static <T extends BaseDataType> T function(Class<?> def,
                                                     Object   referent, 
                                                     String   legacyName, 
                                                     Class<T> cls, 
                                                     Block    block)
   {
      return (T) function(def, referent, legacyName, cls, TransactionType.SUB, block);
   }
   
   /**
    * Execute the given function block with the given transaction level.
    *
    * @param    def
    *           The Java class associated with a legacy OE class, if this code is part of a legacy
    *           OE class; otherwise, <code>null</code>.
    * @param    referent
    *           The referent to which this method belongs.
    * @param    legacyName
    *           The legacy name associated with the function being invoked via a java-style call. 
    *           If is <code>null</code>, it will be resolved by 
    *           {@link ProcedureManager#resolveClosestMethod}.
    * @param    cls
    *           The function's return type.
    * @param    lvl
    *           The transaction level for the given block.
    * @param    block
    *           The code to execute.
    *
    * @return   The return value from the block (or its nested blocks) which
    *           is the <code>unknown value</code> by default or on error.
    */
   public static <T extends BaseDataType> T function(Class<?>        def,
                                                     Object          referent,
                                                     String          legacyName,
                                                     Class<T>        cls,
                                                     TransactionType lvl,
                                                     Block           block)
   {
      return (T) functionBlock(def, referent, legacyName, lvl, block, cls, -1);
   }
   
   /**
    * Execute the given function block with a default transaction level of
    * <code>TransactionType.SUB</code>, which returns an extent value.
    *
    * @param    legacyName
    *           The legacy name associated with the function being invoked via a java-style call. 
    *           If is <code>null</code>, it will be resolved by 
    *           {@link ProcedureManager#resolveClosestMethod}.
    * @param    cls
    *           The function's return type.
    * @param    extent
    *           The function's return extent value.
    * @param    block
    *           The code to execute.
    *
    * @return   The return value from the block (or its nested blocks).
    */
   public static <T extends BaseDataType> T[] extentFunction(String   legacyName,
                                                             Class<T> cls,
                                                             int      extent,
                                                             Block    block)
   {
      return (T[]) extentFunction(legacyName, cls, extent, TransactionType.SUB, block);
   }
   
   /**
    * Execute the given function block with the given transaction level, which returns an extent
    * value.
    *
    * @param    legacyName
    *           The legacy name associated with the function being invoked via a java-style call. 
    *           If is <code>null</code>, it will be resolved by 
    *           {@link ProcedureManager#resolveClosestMethod}.
    * @param    cls
    *           The function's return type.
    * @param    extent
    *           The function's return extent value.
    * @param    lvl
    *           The transaction level for the given block.
    * @param    block
    *           The code to execute.
    *
    * @return   The return value from the block (or its nested blocks).
    */
   public static <T extends BaseDataType> T[] extentFunction(String   legacyName,
                                                             Class<T>        cls,
                                                             int             extent,
                                                             TransactionType lvl,
                                                             Block           block)
   {
      return (T[]) functionBlock(null, null, legacyName, lvl, block, cls, extent);
   }
   
   /**
    * Execute the given function block with a default transaction level of
    * <code>TransactionType.SUB</code>, which returns a dynamic extent value.
    *
    * @param    legacyName
    *           The legacy name associated with the function being invoked via a java-style call. 
    *           If is <code>null</code>, it will be resolved by 
    *           {@link ProcedureManager#resolveClosestMethod}.
    * @param    cls
    *           The function's return type.
    * @param    block
    *           The code to execute.
    *
    * @return   The return value from the block (or its nested blocks).
    */
   public static <T extends BaseDataType> T[] extentFunction(String   legacyName,
                                                             Class<T> cls,
                                                             Block    block)
   {
      return (T[]) extentFunction(legacyName, cls, TransactionType.SUB, block);
   }
   
   /**
    * Execute the given function block with the given transaction level, which returns a 
    * dynamic extent value.
    *
    * @param    legacyName
    *           The legacy name associated with the function being invoked via a java-style call. 
    *           If is <code>null</code>, it will be resolved by 
    *           {@link ProcedureManager#resolveClosestMethod}.
    * @param    cls
    *           The function's return type.
    * @param    lvl
    *           The transaction level for the given block.
    * @param    block
    *           The code to execute.
    *
    * @return   The return value from the block (or its nested blocks).
    */
   public static <T extends BaseDataType> T[] extentFunction(String          legacyName,
                                                             Class<T>        cls,
                                                             TransactionType lvl,
                                                             Block           block)
   {
      return (T[]) functionBlock(null, null, legacyName, lvl, block, cls, 0);
   }
   
   /**
    * Execute the given function block with a default transaction level of
    * <code>TransactionType.SUB</code>, which returns an extent value.
    *
    * @param    referent
    *           The referent to which this method belongs.
    * @param    legacyName
    *           The legacy name associated with the function being invoked via a java-style call. 
    *           If is <code>null</code>, it will be resolved by 
    *           {@link ProcedureManager#resolveClosestMethod}.
    * @param    cls
    *           The function's return type.
    * @param    extent
    *           The function's return extent value.
    * @param    block
    *           The code to execute.
    *
    * @return   The return value from the block (or its nested blocks).
    */
   public static <T extends BaseDataType> T[] extentFunction(Object   referent,
                                                             String   legacyName,
                                                             Class<T> cls,
                                                             int      extent,
                                                             Block    block)
   {
      return (T[]) extentFunction(null, referent, legacyName, cls, extent, TransactionType.SUB, block);
   }
   
   /**
    * Execute the given function block with a default transaction level of
    * <code>TransactionType.SUB</code>, which returns an extent value.
    *
    * @param    def
    *           The Java class associated with a legacy OE class, if this code is part of a legacy
    *           OE class; otherwise, <code>null</code>.
    * @param    referent
    *           The referent to which this method belongs.
    * @param    legacyName
    *           The legacy name associated with the function being invoked via a java-style call. 
    *           If is <code>null</code>, it will be resolved by 
    *           {@link ProcedureManager#resolveClosestMethod}.
    * @param    cls
    *           The function's return type.
    * @param    extent
    *           The function's return extent value.
    * @param    block
    *           The code to execute.
    *
    * @return   The return value from the block (or its nested blocks).
    */
   public static <T extends BaseDataType> T[] extentFunction(Class<?> def,
                                                             Object   referent,
                                                             String   legacyName,
                                                             Class<T> cls,
                                                             int      extent,
                                                             Block    block)
   {
      return (T[]) extentFunction(def, referent, legacyName, cls, extent, TransactionType.SUB, block);
   }
   
   /**
    * Execute the given function block with the given transaction level, which returns an extent
    * value.
    *
    * @param    def
    *           The Java class associated with a legacy OE class, if this code is part of a legacy
    *           OE class; otherwise, <code>null</code>.
    * @param    referent
    *           The referent to which this method belongs.
    * @param    legacyName
    *           The legacy name associated with the function being invoked via a java-style call. 
    *           If is <code>null</code>, it will be resolved by 
    *           {@link ProcedureManager#resolveClosestMethod}.
    * @param    cls
    *           The function's return type.
    * @param    extent
    *           The function's return extent value.
    * @param    lvl
    *           The transaction level for the given block.
    * @param    block
    *           The code to execute.
    *
    * @return   The return value from the block (or its nested blocks).
    */
   public static <T extends BaseDataType> T[] extentFunction(Class<?>        def,
                                                             Object          referent,
                                                             String          legacyName,
                                                             Class<T>        cls,
                                                             int             extent,
                                                             TransactionType lvl,
                                                             Block           block)
   {
      return (T[]) functionBlock(def, referent, legacyName, lvl, block, cls, extent);
   }
   
   /**
    * Execute the given function block with a default transaction level of
    * <code>TransactionType.SUB</code>, which returns a dynamic extent value.
    *
    * @param    referent
    *           The referent to which this method belongs.
    * @param    legacyName
    *           The legacy name associated with the function being invoked via a java-style call. 
    *           If is <code>null</code>, it will be resolved by 
    *           {@link ProcedureManager#resolveClosestMethod}.
    * @param    cls
    *           The function's return type.
    * @param    block
    *           The code to execute.
    *
    * @return   The return value from the block (or its nested blocks).
    */
   public static <T extends BaseDataType> T[] extentFunction(Object   referent,
                                                             String   legacyName,
                                                             Class<T> cls,
                                                             Block    block)
   {
      return (T[]) extentFunction(referent, legacyName, cls, TransactionType.SUB, block);
   }
   
   /**
    * Execute the given function block with a default transaction level of
    * <code>TransactionType.SUB</code>, which returns a dynamic extent value.
    *
    * @param    def
    *           The Java class associated with a legacy OE class, if this code is part of a legacy
    *           OE class; otherwise, <code>null</code>.
    * @param    referent
    *           The referent to which this method belongs.
    * @param    legacyName
    *           The legacy name associated with the function being invoked via a java-style call. 
    *           If is <code>null</code>, it will be resolved by 
    *           {@link ProcedureManager#resolveClosestMethod}.
    * @param    cls
    *           The function's return type.
    * @param    block
    *           The code to execute.
    *
    * @return   The return value from the block (or its nested blocks).
    */
   public static <T extends BaseDataType> T[] extentFunction(Class<?> def,
                                                             Object   referent,
                                                             String   legacyName,
                                                             Class<T> cls,
                                                             Block    block)
   {
      return (T[]) extentFunction(def, referent, legacyName, cls, TransactionType.SUB, block);
   }
   
   /**
    * Execute the given function block with the given transaction level, which returns a 
    * dynamic extent value.
    *
    * @param    referent
    *           The referent to which this method belongs.
    * @param    legacyName
    *           The legacy name associated with the function being invoked via a java-style call. 
    *           If is <code>null</code>, it will be resolved by 
    *           {@link ProcedureManager#resolveClosestMethod}.
    * @param    cls
    *           The function's return type.
    * @param    lvl
    *           The transaction level for the given block.
    * @param    block
    *           The code to execute.
    *
    * @return   The return value from the block (or its nested blocks).
    */
   public static <T extends BaseDataType> T[] extentFunction(Object          referent,
                                                             String          legacyName,
                                                             Class<T>        cls,
                                                             TransactionType lvl,
                                                             Block           block)
   {
      return (T[]) functionBlock(null, referent, legacyName, lvl, block, cls, 0);
   }
   
   /**
    * Execute the given function block with the given transaction level, which returns a 
    * dynamic extent value.
    *
    * @param    def
    *           The Java class associated with a legacy OE class, if this code is part of a legacy
    *           OE class; otherwise, <code>null</code>.
    * @param    referent
    *           The referent to which this method belongs.
    * @param    legacyName
    *           The legacy name associated with the function being invoked via a java-style call. 
    *           If is <code>null</code>, it will be resolved by 
    *           {@link ProcedureManager#resolveClosestMethod}.
    * @param    cls
    *           The function's return type.
    * @param    lvl
    *           The transaction level for the given block.
    * @param    block
    *           The code to execute.
    *
    * @return   The return value from the block (or its nested blocks).
    */
   public static <T extends BaseDataType> T[] extentFunction(Class<?>        def,
                                                             Object          referent,
                                                             String          legacyName,
                                                             Class<T>        cls,
                                                             TransactionType lvl,
                                                             Block           block)
   {
      return (T[]) functionBlock(def, referent, legacyName, lvl, block, cls, 0);
   }

   /**
    * Execute a simple DO block (not a loop) with the given configuration
    * and no default properties. <code>TransactionType.NONE</code> will be
    * used and there are no enclosing non-managed blocks. In addition, there
    * are no user-defined properties.
    *
    * @param    label
    *           The block name of the current block.
    * @param    block
    *           The code to execute.
    */
   public static void doBlock(String label, Block block)
   {
      doBlockWorker(TransactionType.NONE, null, label, null, block);
   }
   
   /**
    * Execute a simple DO block (not a loop) with the given configuration
    * and no default properties. <code>TransactionType.NONE</code> will be
    * used and there are no user-defined properties.
    *
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    block
    *           The code to execute.
    */
   public static void doBlock(String[] enclosing, String label, Block block)
   {
      doBlockWorker(TransactionType.NONE, enclosing, label, null, block);
   }
   
   /**
    * Execute a simple DO block (not a loop) with the given configuration
    * and no user-defined or default properties. In addition, there are no
    * enclosing non-managed blocks.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    label
    *           The block name of the current block.
    * @param    block
    *           The code to execute.
    */
   public static void doBlock(TransactionType lvl, String label, Block block)
   {
      doBlockWorker(lvl, null, label, null, block);
   }
   
   /**
    * Execute a simple DO block (not a loop) with the given configuration
    * and no user-defined or default properties.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    block
    *           The code to execute.
    */
   public static void doBlock(TransactionType lvl,
                              String[]        enclosing,
                              String          label,
                              Block           block)
   {
      doBlockWorker(lvl, enclosing, label, null, block);
   }

   /**
    * Execute a simple DO block (not a loop) with the given configuration
    * and no default properties. <code>TransactionType.NONE</code> will be
    * used and there are no enclosing non-managed blocks.
    *
    * @param    label
    *           The block name of the current block.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void doBlock(String label, OnPhrase[] on, Block block)
   {
      doBlockWorker(TransactionType.NONE, null, label, on, block);
   }
   
   /**
    * Execute a simple DO block (not a loop) with the given configuration
    * and no default properties. <code>TransactionType.NONE</code> will be
    * used.
    *
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void doBlock(String[]   enclosing,
                              String     label,
                              OnPhrase[] on,
                              Block      block)
   {
      doBlockWorker(TransactionType.NONE, enclosing, label, on, block);
   }
   
   /**
    * Execute a simple DO block (not a loop) with the given configuration
    * and no default properties. In this case, there are no enclosing
    * non-managed blocks.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    label
    *           The block name of the current block.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void doBlock(TransactionType lvl,
                              String          label,
                              OnPhrase[]      on,
                              Block           block)
   {
      doBlockWorker(lvl, null, label, on, block);
   }
   
   /**                                              
    * Execute a simple DO block (not a loop) with the given configuration
    * and no default properties.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void doBlock(TransactionType lvl,
                              String[]        enclosing,
                              String          label,
                              OnPhrase[]      on,
                              Block           block)
   {
      doBlockWorker(lvl, enclosing, label, on, block);
   }
   
   /**
    * Execute a DO WHILE expression loop with the given configuration
    * and no default properties. <code>TransactionType.NONE</code> will be
    * used and there are no enclosing non-managed blocks. In addition, there
    * are no user-defined properties.
    *
    * @param    label
    *           The block name of the current block.
    * @param    expr
    *           The WHILE clause that defines the loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    block
    *           The code to execute.
    */
   public static void doWhile(String label, LogicalOp expr, Block block)
   {
      doLoopWorker(TransactionType.NONE, null, label, null, expr, null, block);
   }
   
   /**
    * Execute a DO WHILE expression loop with the given configuration
    * and no default properties. <code>TransactionType.NONE</code> will be
    * used and there are no user-defined properties.
    *
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    expr
    *           The WHILE clause that defines the loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    block
    *           The code to execute.
    */
   public static void doWhile(String[] enclosing, String label, LogicalOp expr, Block block)
   {
      doLoopWorker(TransactionType.NONE, enclosing, label, null, expr, null, block);
   }
   
   /**
    * Execute a DO WHILE expression loop with the given configuration
    * and no user-defined or default properties. In addition, there are no
    * enclosing non-managed blocks.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    label
    *           The block name of the current block.
    * @param    expr
    *           The WHILE clause that defines the loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    block
    *           The code to execute.
    */
   public static void doWhile(TransactionType lvl, String label, LogicalOp expr, Block block)
   {
      doLoopWorker(lvl, null, label, null, expr, null, block);
   }
   
   /**
    * Execute a DO WHILE expression loop with the given configuration
    * and no user-defined or default properties.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    expr
    *           The WHILE clause that defines the loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    block
    *           The code to execute.
    */
   public static void doWhile(TransactionType lvl,
                              String[]        enclosing,
                              String          label,
                              LogicalOp       expr,
                              Block           block)
   {
      doLoopWorker(lvl, enclosing, label, null, expr, null, block);
   }

   /**
    * Execute a DO WHILE expression loop with the given configuration
    * and no default properties. <code>TransactionType.NONE</code> will be
    * used and there are no enclosing non-managed blocks.
    *
    * @param    label
    *           The block name of the current block.
    * @param    expr
    *           The WHILE clause that defines the loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void doWhile(String label, LogicalOp expr, OnPhrase[] on, Block block)
   {
      doLoopWorker(TransactionType.NONE, null, label, null, expr, on, block);
   }
   
   /**
    * Execute a DO WHILE expression loop with the given configuration
    * and no default properties. <code>TransactionType.NONE</code> will be
    * used.
    *
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    expr
    *           The WHILE clause that defines the loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void doWhile(String[]   enclosing,
                              String     label,
                              LogicalOp  expr,
                              OnPhrase[] on,
                              Block      block)
   {
      doLoopWorker(TransactionType.NONE, enclosing, label, null, expr, on, block);
   }
   
   /**
    * Execute a DO WHILE expression loop with the given configuration
    * and no default properties. In this case, there are no enclosing
    * non-managed blocks.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    label
    *           The block name of the current block.
    * @param    expr
    *           The WHILE clause that defines the loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void doWhile(TransactionType lvl,
                              String          label,
                              LogicalOp       expr,
                              OnPhrase[]      on,
                              Block           block)
   {
      doLoopWorker(lvl, null, label, null, expr, on, block);
   }
   
   /**
    * Execute a DO WHILE expression loop with the given configuration
    * and no default properties.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    expr      
    *           The WHILE clause that defines the loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void doWhile(TransactionType lvl,
                              String[]        enclosing,
                              String          label,
                              LogicalOp       expr,
                              OnPhrase[]      on,
                              Block           block)
   {
      doLoopWorker(lvl, enclosing, label, null, expr, on, block);
   }
             
   /**
    * Execute a DO TO expression loop with the given configuration
    * and no default properties. <code>TransactionType.NONE</code> will be
    * used and there are no enclosing non-managed blocks. In addition, there
    * are no user-defined properties.
    *
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    block
    *           The code to execute.
    */
   public static void doTo(String label, ToClause to, Block block)
   {
      doLoopWorker(TransactionType.NONE, null, label, to, null, null, block);
   }
   
   /**
    * Execute a DO TO expression loop with the given configuration
    * and no default properties. <code>TransactionType.NONE</code> will be
    * used and there are no user-defined properties.
    *
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    block
    *           The code to execute.
    */
   public static void doTo(String[] enclosing,
                           String   label,
                           ToClause to,
                           Block    block)
   {
      doLoopWorker(TransactionType.NONE, enclosing, label, to, null, null, block);
   }
   
   /**
    * Execute a DO TO expression loop with the given configuration
    * and no user-defined or default properties. In addition, there are no
    * enclosing non-managed blocks.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    block
    *           The code to execute.
    */
   public static void doTo(TransactionType lvl,
                           String          label,
                           ToClause        to,
                           Block           block)
   {
      doLoopWorker(lvl, null, label, to, null, null, block);
   }
   
   /**
    * Execute a DO TO expression loop with the given configuration
    * and no user-defined or default properties.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    block
    *           The code to execute.
    */
   public static void doTo(TransactionType lvl,
                           String[]        enclosing,
                           String          label,
                           ToClause        to,
                           Block           block)
   {
      doLoopWorker(lvl, enclosing, label, to, null, null, block);
   }

   /**
    * Execute a DO TO expression loop with the given configuration
    * and no default properties. <code>TransactionType.NONE</code> will be
    * used and there are no enclosing non-managed blocks.
    *
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void doTo(String     label,
                           ToClause   to,
                           OnPhrase[] on,
                           Block      block)
   {
      doLoopWorker(TransactionType.NONE, null, label, to, null, on, block);
   }
   
   /**
    * Execute a DO TO expression loop with the given configuration
    * and no default properties. <code>TransactionType.NONE</code> will be
    * used.
    *
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void doTo(String[]   enclosing,
                           String     label,
                           ToClause   to,
                           OnPhrase[] on,
                           Block      block)
   {
      doLoopWorker(TransactionType.NONE, enclosing, label, to, null, on, block);
   }
   
   /**
    * Execute a DO TO expression loop with the given configuration
    * and no default properties. In this case, there are no enclosing
    * non-managed blocks.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void doTo(TransactionType lvl,
                           String          label,
                           ToClause        to,
                           OnPhrase[]      on,
                           Block           block)
   {
      doLoopWorker(lvl, null, label, to, null, on, block);
   }
   
   /**
    * Execute a DO TO expression loop with the given configuration
    * and no default properties.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void doTo(TransactionType lvl,
                           String[]        enclosing,
                           String          label,
                           ToClause        to,
                           OnPhrase[]      on,
                           Block           block)
   {
      doLoopWorker(lvl, enclosing, label, to, null, on, block);
   }
   
   /**
    * Execute a DO WHILE expression, DO TO var = val1 to val2 by val3 or DO
    * TO WHILE expression loop with the given configuration and no default
    * properties.  At least one of the to clause or while expression must be
    * passed and it is valid to have both passed in which case both of the
    * conditions are tested with a logical AND.
    * <p>
    * <code>TransactionType.NONE</code> will be used and there are no
    * enclosing non-managed blocks. In addition, there are no user-defined
    * properties.
    *
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends. If this is <code>null</code>,
    *           then a WHILE clause MUST be present to provide the condition
    *           for maintaining the loop.
    * @param    expr      
    *           The WHILE clause that defines a loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>. If this is
    *           <code>null</code>, then a TO clause MUST be present to
    *           provide the condition for maintaining the loop.
    * @param    block
    *           The code to execute.
    */
   public static void doToWhile(String label, ToClause to, LogicalOp expr, Block block)
   {
      doLoopWorker(TransactionType.NONE, null, label, to, expr, null, block);
   }
   
   /**
    * Execute a DO WHILE expression, DO TO var = val1 to val2 by val3 or DO
    * TO WHILE expression loop with the given configuration and no default
    * properties.  At least one of the to clause or while expression must be
    * passed and it is valid to have both passed in which case both of the
    * conditions are tested with a logical AND.
    * <p>
    * <code>TransactionType.NONE</code> will be used and there are no
    * user-defined properties.
    *
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends. If this is <code>null</code>,
    *           then a WHILE clause MUST be present to provide the condition
    *           for maintaining the loop.
    * @param    expr      
    *           The WHILE clause that defines a loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>. If this is
    *           <code>null</code>, then a TO clause MUST be present to
    *           provide the condition for maintaining the loop.
    * @param    block
    *           The code to execute.
    */
   public static void doToWhile(String[]  enclosing,
                                String    label,
                                ToClause  to,
                                LogicalOp expr,
                                Block     block)
   {
      doLoopWorker(TransactionType.NONE, enclosing, label, to, expr, null, block);
   }
   
   /**
    * Execute a DO WHILE expression, DO TO var = val1 to val2 by val3 or DO
    * TO WHILE expression loop with the given configuration and no default
    * properties.  At least one of the to clause or while expression must be
    * passed and it is valid to have both passed in which case both of the
    * conditions are tested with a logical AND.
    * <p>
    * There are no user-defined properties and no enclosing non-managed
    * blocks.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends. If this is <code>null</code>,
    *           then a WHILE clause MUST be present to provide the condition
    *           for maintaining the loop.
    * @param    expr      
    *           The WHILE clause that defines a loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>. If this is
    *           <code>null</code>, then a TO clause MUST be present to
    *           provide the condition for maintaining the loop.
    * @param    block
    *           The code to execute.
    */
   public static void doToWhile(TransactionType lvl,
                                String          label,
                                ToClause        to,
                                LogicalOp       expr,
                                Block           block)
   {
      doLoopWorker(lvl, null, label, to, expr, null, block);
   }
   
   /**
    * Execute a DO WHILE expression, DO TO var = val1 to val2 by val3 or DO
    * TO WHILE expression loop with the given configuration and no default
    * properties.  At least one of the to clause or while expression must be
    * passed and it is valid to have both passed in which case both of the
    * conditions are tested with a logical AND.
    * <p>
    * There are no user-defined properties.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends. If this is <code>null</code>,
    *           then a WHILE clause MUST be present to provide the condition
    *           for maintaining the loop.
    * @param    expr      
    *           The WHILE clause that defines a loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>. If this is
    *           <code>null</code>, then a TO clause MUST be present to
    *           provide the condition for maintaining the loop.
    * @param    block
    *           The code to execute.
    */
   public static void doToWhile(TransactionType lvl,
                                String[]        enclosing,
                                String          label,
                                ToClause        to,
                                LogicalOp       expr,
                                Block           block)
   {
      doLoopWorker(lvl, enclosing, label, to, expr, null, block);
   }

   /**
    * Execute a DO WHILE expression, DO TO var = val1 to val2 by val3 or DO
    * TO WHILE expression loop with the given configuration and no default
    * properties.  At least one of the to clause or while expression must be
    * passed and it is valid to have both passed in which case both of the
    * conditions are tested with a logical AND.
    * <p>
    * <code>TransactionType.NONE</code> will be used and there are no
    * enclosing non-managed blocks.
    *
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends. If this is <code>null</code>,
    *           then a WHILE clause MUST be present to provide the condition
    *           for maintaining the loop.
    * @param    expr      
    *           The WHILE clause that defines a loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>. If this is
    *           <code>null</code>, then a TO clause MUST be present to
    *           provide the condition for maintaining the loop.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void doToWhile(String     label,
                                ToClause   to,
                                LogicalOp  expr,
                                OnPhrase[] on,
                                Block      block)
   {
      doLoopWorker(TransactionType.NONE, null, label, to, expr, on, block);
   }
   
   /**
    * Execute a DO WHILE expression, DO TO var = val1 to val2 by val3 or DO
    * TO WHILE expression loop with the given configuration and no default
    * properties.  At least one of the to clause or while expression must be
    * passed and it is valid to have both passed in which case both of the
    * conditions are tested with a logical AND.
    * <p>
    * <code>TransactionType.NONE</code> will be used.
    *
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends. If this is <code>null</code>,
    *           then a WHILE clause MUST be present to provide the condition
    *           for maintaining the loop.
    * @param    expr      
    *           The WHILE clause that defines a loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>. If this is
    *           <code>null</code>, then a TO clause MUST be present to
    *           provide the condition for maintaining the loop.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void doToWhile(String[]   enclosing,
                                String     label,
                                ToClause   to,
                                LogicalOp  expr,
                                OnPhrase[] on,
                                Block      block)
   {
      doLoopWorker(TransactionType.NONE, enclosing, label, to, expr, on, block);
   }
   
   /**
    * Execute a DO WHILE expression, DO TO var = val1 to val2 by val3 or DO
    * TO WHILE expression loop with the given configuration and no default
    * properties.  At least one of the to clause or while expression must be
    * passed and it is valid to have both passed in which case both of the
    * conditions are tested with a logical AND.
    * <p>
    * There are no enclosing non-managed blocks.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends. If this is <code>null</code>,
    *           then a WHILE clause MUST be present to provide the condition
    *           for maintaining the loop.
    * @param    expr      
    *           The WHILE clause that defines a loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>. If this is
    *           <code>null</code>, then a TO clause MUST be present to
    *           provide the condition for maintaining the loop.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void doToWhile(TransactionType lvl,
                                String          label,
                                ToClause        to,
                                LogicalOp       expr,
                                OnPhrase[]      on,
                                Block           block)
   {
      doLoopWorker(lvl, null, label, to, expr, on, block);
   }
   
   /**
    * Execute a DO WHILE expression, DO TO var = val1 to val2 by val3 or DO
    * TO WHILE expression loop with the given configuration and no default
    * properties.  At least one of the to clause or while expression must be
    * passed and it is valid to have both passed in which case both of the
    * conditions are tested with a logical AND.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends. If this is <code>null</code>,
    *           then a WHILE clause MUST be present to provide the condition
    *           for maintaining the loop.
    * @param    expr      
    *           The WHILE clause that defines a loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>. If this is
    *           <code>null</code>, then a TO clause MUST be present to
    *           provide the condition for maintaining the loop.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void doToWhile(TransactionType lvl,
                                String[]        enclosing,
                                String          label,
                                ToClause        to,
                                LogicalOp       expr,
                                OnPhrase[]      on,
                                Block           block)
   {
      doLoopWorker(lvl, enclosing, label, to, expr, on, block);
   }
             
   /**
    * Execute a simple REPEAT (infinite loop) with the given configuration
    * and default properties. <code>TransactionType.SUB</code> will be
    * used and there are no enclosing non-managed blocks. In addition, there
    * are no user-defined properties.
    *
    * @param    label
    *           The block name of the current block.
    * @param    block
    *           The code to execute.
    */
   public static void repeat(String label, Block block)
   {
      repeatWorker(TransactionType.SUB, null, label, null, null, null, block);
   }
   
   /**
    * Execute a simple REPEAT (infinite loop) with the given configuration
    * and default properties. <code>TransactionType.SUB</code> will be
    * used and there are no user-defined properties.
    *
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    block
    *           The code to execute.
    */
   public static void repeat(String[] enclosing, String label, Block block)
   {
      repeatWorker(TransactionType.SUB, enclosing, label, null, null, null, block);
   }
   
   /**
    * Execute a simple REPEAT (infinite loop) with the given configuration
    * and default properties.  There are no user-defined properties and
    * there are no enclosing non-managed blocks.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    label
    *           The block name of the current block.
    * @param    block
    *           The code to execute.
    */
   public static void repeat(TransactionType lvl, String label, Block block)
   {
      repeatWorker(lvl, null, label, null, null, null, block);
   }
   
   /**
    * Execute a simple REPEAT (infinite loop) with the given configuration
    * and default properties.  There are no user-defined properties.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    block
    *           The code to execute.
    */
   public static void repeat(TransactionType lvl,
                             String[]        enclosing,
                             String          label,
                             Block           block)
   {
      repeatWorker(lvl, enclosing, label, null, null, null, block);
   }

   /**
    * Execute a simple REPEAT (infinite loop) with the given configuration
    * and default properties.  <code>TransactionType.SUB</code> will be used
    * and there are no enclosing non-managed blocks.
    *
    * @param    label
    *           The block name of the current block.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void repeat(String label, OnPhrase[] on, Block block)
   {
      repeatWorker(TransactionType.SUB, null, label, null, null, on, block);
   }
   
   /**
    * Execute a simple REPEAT (infinite loop) with the given configuration
    * and default properties.  <code>TransactionType.SUB</code> will be used.
    *
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void repeat(String[]   enclosing,
                             String     label,
                             OnPhrase[] on,
                             Block      block)
   {
      repeatWorker(TransactionType.SUB, enclosing, label, null, null, on, block);
   }
   
   /**
    * Execute a simple REPEAT (infinite loop) with the given configuration
    * and default properties. In this case, there are no enclosing
    * non-managed blocks.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    label
    *           The block name of the current block.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void repeat(TransactionType lvl,
                             String          label,
                             OnPhrase[]      on,
                             Block           block)
   {
      repeatWorker(lvl, null, label, null, null, on, block);
   }
   
   /**                                              
    * Execute a simple REPEAT (infinite loop) with the given configuration
    * and default properties.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void repeat(TransactionType lvl,
                             String[]        enclosing,
                             String          label,
                             OnPhrase[]      on,
                             Block           block)
   {
      repeatWorker(lvl, enclosing, label, null, null, on, block);
   }
   
   /**
    * Execute a REPEAT WHILE expression loop with the given configuration
    * and default properties. <code>TransactionType.SUB</code> will be
    * used and there are no enclosing non-managed blocks. In addition, there
    * are no user-defined properties.
    *
    * @param    label
    *           The block name of the current block.
    * @param    expr
    *           The WHILE clause that defines the loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    block
    *           The code to execute.
    */
   public static void repeatWhile(String label, LogicalOp expr, Block block)
   {
      repeatWorker(TransactionType.SUB, null, label, null, expr, null, block);
   }
   
   /**
    * Execute a REPEAT WHILE expression loop with the given configuration
    * and default properties. <code>TransactionType.SUB</code> will be
    * used and there are no user-defined properties.
    *
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    expr
    *           The WHILE clause that defines the loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    block
    *           The code to execute.
    */
   public static void repeatWhile(String[] enclosing, String label, LogicalOp expr, Block block)
   {
      repeatWorker(TransactionType.SUB, enclosing, label, null, expr, null, block);
   }
   
   /**
    * Execute a REPEAT WHILE expression loop with the given configuration
    * and no user-defined or default properties. In addition, there are no
    * enclosing non-managed blocks.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    label
    *           The block name of the current block.
    * @param    expr
    *           The WHILE clause that defines the loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    block
    *           The code to execute.
    */
   public static void repeatWhile(TransactionType lvl, String label, LogicalOp expr, Block block)
   {
      repeatWorker(lvl, null, label, null, expr, null, block);
   }
   
   /**
    * Execute a REPEAT WHILE expression loop with the given configuration
    * and no user-defined or default properties.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    expr
    *           The WHILE clause that defines the loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    block
    *           The code to execute.
    */
   public static void repeatWhile(TransactionType lvl,
                                  String[]        enclosing,
                                  String          label,
                                  LogicalOp       expr,
                                  Block           block)
   {
      repeatWorker(lvl, enclosing, label, null, expr, null, block);
   }

   /**
    * Execute a REPEAT WHILE expression loop with the given configuration
    * and default properties. <code>TransactionType.SUB</code> will be
    * used and there are no enclosing non-managed blocks.
    *
    * @param    label
    *           The block name of the current block.
    * @param    expr
    *           The WHILE clause that defines the loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void repeatWhile(String label, LogicalOp expr, OnPhrase[] on, Block block)
   {
      repeatWorker(TransactionType.SUB, null, label, null, expr, on, block);
   }
   
   /**
    * Execute a REPEAT WHILE expression loop with the given configuration
    * and default properties. <code>TransactionType.SUB</code> will be
    * used.
    *
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    expr
    *           The WHILE clause that defines the loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void repeatWhile(String[]   enclosing,
                                  String     label,
                                  LogicalOp  expr,
                                  OnPhrase[] on,
                                  Block      block)
   {
      repeatWorker(TransactionType.SUB, enclosing, label, null, expr, on, block);
   }
   
   /**
    * Execute a REPEAT WHILE expression loop with the given configuration
    * and default properties. In this case, there are no enclosing
    * non-managed blocks.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    label
    *           The block name of the current block.
    * @param    expr
    *           The WHILE clause that defines the loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void repeatWhile(TransactionType lvl,
                                  String          label,
                                  LogicalOp       expr,
                                  OnPhrase[]      on,
                                  Block           block)
   {
      repeatWorker(lvl, null, label, null, expr, on, block);
   }
   
   /**
    * Execute a REPEAT WHILE expression loop with the given configuration
    * and default properties.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    expr      
    *           The WHILE clause that defines the loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void repeatWhile(TransactionType lvl,
                                  String[]        enclosing,
                                  String          label,
                                  LogicalOp       expr,
                                  OnPhrase[]      on,
                                  Block           block)
   {
      repeatWorker(lvl, enclosing, label, null, expr, on, block);
   }
             
   /**
    * Execute a REPEAT TO expression loop with the given configuration
    * and default properties. <code>TransactionType.SUB</code> will be
    * used and there are no enclosing non-managed blocks. In addition, there
    * are no user-defined properties.
    *
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    block
    *           The code to execute.
    */
   public static void repeatTo(String label, ToClause to, Block block)
   {
      repeatWorker(TransactionType.SUB, null, label, to, null, null, block);
   }
   
   /**
    * Execute a REPEAT TO expression loop with the given configuration
    * and default properties. <code>TransactionType.SUB</code> will be
    * used and there are no user-defined properties.
    *
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    block
    *           The code to execute.
    */
   public static void repeatTo(String[] enclosing,
                               String   label,
                               ToClause to,
                               Block    block)
   {
      repeatWorker(TransactionType.SUB, enclosing, label, to, null, null, block);
   }
   
   /**
    * Execute a REPEAT TO expression loop with the given configuration
    * and no user-defined or default properties. In addition, there are no
    * enclosing non-managed blocks.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    block
    *           The code to execute.
    */
   public static void repeatTo(TransactionType lvl,
                               String          label,
                               ToClause        to,
                               Block           block)
   {
      repeatWorker(lvl, null, label, to, null, null, block);
   }
   
   /**
    * Execute a REPEAT TO expression loop with the given configuration
    * and no user-defined or default properties.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    block
    *           The code to execute.
    */
   public static void repeatTo(TransactionType lvl,
                               String[]        enclosing,
                               String          label,
                               ToClause        to,
                               Block           block)
   {
      repeatWorker(lvl, enclosing, label, to, null, null, block);
   }

   /**
    * Execute a REPEAT TO expression loop with the given configuration
    * and default properties. <code>TransactionType.SUB</code> will be
    * used and there are no enclosing non-managed blocks.
    *
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void repeatTo(String     label,
                               ToClause   to,
                               OnPhrase[] on,
                               Block      block)
   {
      repeatWorker(TransactionType.SUB, null, label, to, null, on, block);
   }
   
   /**
    * Execute a REPEAT TO expression loop with the given configuration
    * and default properties. <code>TransactionType.SUB</code> will be
    * used.
    *
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void repeatTo(String[]   enclosing,
                               String     label,
                               ToClause   to,
                               OnPhrase[] on,
                               Block      block)
   {
      repeatWorker(TransactionType.SUB, enclosing, label, to, null, on, block);
   }
   
   /**
    * Execute a REPEAT TO expression loop with the given configuration
    * and default properties. In this case, there are no enclosing
    * non-managed blocks.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void repeatTo(TransactionType lvl,
                               String          label,
                               ToClause        to,
                               OnPhrase[]      on,
                               Block           block)
   {
      repeatWorker(lvl, null, label, to, null, on, block);
   }
   
   /**
    * Execute a REPEAT TO expression loop with the given configuration
    * and default properties.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void repeatTo(TransactionType lvl,
                               String[]        enclosing,
                               String          label,
                               ToClause        to,
                               OnPhrase[]      on,
                               Block           block)
   {
      repeatWorker(lvl, enclosing, label, to, null, on, block);
   }
   
   /**
    * Execute a REPEAT WHILE expression, REPEAT TO var = val1 to val2 by val3
    * or REPEAT TO WHILE expression loop with the given configuration and
    * default properties. At least one of the to clause or while expression
    * must be passed and it is valid to have both passed in which case both
    * of the conditions are tested with a logical AND.
    * <p>
    * <code>TransactionType.SUB</code> will be used and there are no
    * enclosing non-managed blocks. In addition, there are no user-defined
    * properties.
    *
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends. If this is <code>null</code>,
    *           then a WHILE clause MUST be present to provide the condition
    *           for maintaining the loop.
    * @param    expr      
    *           The WHILE clause that defines a loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>. If this is
    *           <code>null</code>, then a TO clause MUST be present to
    *           provide the condition for maintaining the loop.
    * @param    block
    *           The code to execute.
    */
   public static void repeatToWhile(String label, ToClause to, LogicalOp expr, Block block)
   {
      repeatWorker(TransactionType.SUB, null, label, to, expr, null, block);
   }
   
   /**
    * Execute a REPEAT WHILE expression, REPEAT TO var = val1 to val2 by val3
    * or REPEAT TO WHILE expression loop with the given configuration and
    * default properties. At least one of the to clause or while expression
    * must be passed and it is valid to have both passed in which case both
    * of the conditions are tested with a logical AND.
    * <p>
    * <code>TransactionType.SUB</code> will be used and there are no
    * user-defined properties.
    *
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends. If this is <code>null</code>,
    *           then a WHILE clause MUST be present to provide the condition
    *           for maintaining the loop.
    * @param    expr      
    *           The WHILE clause that defines a loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>. If this is
    *           <code>null</code>, then a TO clause MUST be present to
    *           provide the condition for maintaining the loop.
    * @param    block
    *           The code to execute.
    */
   public static void repeatToWhile(String[]  enclosing,
                                    String    label,
                                    ToClause  to,
                                    LogicalOp expr,
                                    Block     block)
   {
      repeatWorker(TransactionType.SUB, enclosing, label, to, expr, null, block);
   }
   
   /**
    * Execute a REPEAT WHILE expression, REPEAT TO var = val1 to val2 by val3
    * or REPEAT TO WHILE expression loop with the given configuration and
    * default properties. At least one of the to clause or while expression
    * must be passed and it is valid to have both passed in which case both
    * of the conditions are tested with a logical AND.
    * <p>
    * There are no user-defined properties and no enclosing non-managed
    * blocks.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends. If this is <code>null</code>,
    *           then a WHILE clause MUST be present to provide the condition
    *           for maintaining the loop.
    * @param    expr      
    *           The WHILE clause that defines a loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>. If this is
    *           <code>null</code>, then a TO clause MUST be present to
    *           provide the condition for maintaining the loop.
    * @param    block
    *           The code to execute.
    */
   public static void repeatToWhile(TransactionType lvl,
                                    String          label,
                                    ToClause        to,
                                    LogicalOp       expr,
                                    Block           block)
   {
      repeatWorker(lvl, null, label, to, expr, null, block);
   }
   
   /**
    * Execute a REPEAT WHILE expression, REPEAT TO var = val1 to val2 by val3
    * or REPEAT TO WHILE expression loop with the given configuration and
    * default properties. At least one of the to clause or while expression
    * must be passed and it is valid to have both passed in which case both
    * of the conditions are tested with a logical AND.
    * <p>
    * There are no user-defined properties.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends. If this is <code>null</code>,
    *           then a WHILE clause MUST be present to provide the condition
    *           for maintaining the loop.
    * @param    expr      
    *           The WHILE clause that defines a loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>. If this is
    *           <code>null</code>, then a TO clause MUST be present to
    *           provide the condition for maintaining the loop.
    * @param    block
    *           The code to execute.
    */
   public static void repeatToWhile(TransactionType lvl,
                                    String[]        enclosing,
                                    String          label,
                                    ToClause        to,
                                    LogicalOp       expr,
                                    Block           block)
   {
      repeatWorker(lvl, enclosing, label, to, expr, null, block);
   }

   /**
    * Execute a REPEAT WHILE expression, REPEAT TO var = val1 to val2 by val3
    * or REPEAT TO WHILE expression loop with the given configuration and
    * default properties. At least one of the to clause or while expression
    * must be passed and it is valid to have both passed in which case both
    * of the conditions are tested with a logical AND.
    * <p>
    * <code>TransactionType.SUB</code> will be used and there are no
    * enclosing non-managed blocks.
    *
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends. If this is <code>null</code>,
    *           then a WHILE clause MUST be present to provide the condition
    *           for maintaining the loop.
    * @param    expr      
    *           The WHILE clause that defines a loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>. If this is
    *           <code>null</code>, then a TO clause MUST be present to
    *           provide the condition for maintaining the loop.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void repeatToWhile(String     label,
                                    ToClause   to,
                                    LogicalOp  expr,
                                    OnPhrase[] on,
                                    Block      block)
   {
      repeatWorker(TransactionType.SUB, null, label, to, expr, on, block);
   }
   
   /**
    * Execute a REPEAT WHILE expression, REPEAT TO var = val1 to val2 by val3
    * or REPEAT TO WHILE expression loop with the given configuration and
    * default properties. At least one of the to clause or while expression
    * must be passed and it is valid to have both passed in which case both
    * of the conditions are tested with a logical AND.
    * <p>
    * <code>TransactionType.SUB</code> will be used.
    *
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends. If this is <code>null</code>,
    *           then a WHILE clause MUST be present to provide the condition
    *           for maintaining the loop.
    * @param    expr      
    *           The WHILE clause that defines a loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>. If this is
    *           <code>null</code>, then a TO clause MUST be present to
    *           provide the condition for maintaining the loop.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void repeatToWhile(String[]   enclosing,
                                    String     label,
                                    ToClause   to,
                                    LogicalOp  expr,
                                    OnPhrase[] on,
                                    Block      block)
   {
      repeatWorker(TransactionType.SUB, enclosing, label, to, expr, on, block);
   }
   
   /**
    * Execute a REPEAT WHILE expression, REPEAT TO var = val1 to val2 by val3
    * or REPEAT TO WHILE expression loop with the given configuration and
    * default properties.  At least one of the to clause or while expression
    * must be passed and it is valid to have both passed in which case both
    * of the conditions are tested with a logical AND.
    * <p>
    * There are no enclosing non-managed blocks.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends. If this is <code>null</code>,
    *           then a WHILE clause MUST be present to provide the condition
    *           for maintaining the loop.
    * @param    expr      
    *           The WHILE clause that defines a loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>. If this is
    *           <code>null</code>, then a TO clause MUST be present to
    *           provide the condition for maintaining the loop.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void repeatToWhile(TransactionType lvl,
                                    String          label,
                                    ToClause        to,
                                    LogicalOp       expr,
                                    OnPhrase[]      on,
                                    Block           block)
   {
      repeatWorker(lvl, null, label, to, expr, on, block);
   }
   
   /**
    * Execute a REPEAT WHILE expression, REPEAT TO var = val1 to val2 by val3
    * or REPEAT TO WHILE expression loop with the given configuration and
    * default properties.  At least one of the to clause or while expression
    * must be passed and it is valid to have both passed in which case both
    * of the conditions are tested with a logical AND.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends. If this is <code>null</code>,
    *           then a WHILE clause MUST be present to provide the condition
    *           for maintaining the loop.
    * @param    expr      
    *           The WHILE clause that defines a loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>. If this is
    *           <code>null</code>, then a TO clause MUST be present to
    *           provide the condition for maintaining the loop.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void repeatToWhile(TransactionType lvl,
                                    String[]        enclosing,
                                    String          label,
                                    ToClause        to,
                                    LogicalOp       expr,
                                    OnPhrase[]      on,
                                    Block           block)
   {
      repeatWorker(lvl, enclosing, label, to, expr, on, block);
   }
             
   /**
    * Execute a FOR FIRST or FOR LAST block with the given configuration
    * and default properties. <code>TransactionType.SUB</code> will be
    * used and there are no enclosing non-managed blocks. In addition, there
    * are no user-defined properties.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    label
    *           The block name of the current block.
    * @param    block
    *           The code to execute.
    */
   public static void forBlock(P2JQuery query, int direction, String label, Block block)
   {
      forBlockWorker(TransactionType.SUB, query, direction, null, label, null, null, null, block);
   }
   
   /**
    * Execute a FOR FIRST or FOR LAST block with the given configuration
    * and default properties. <code>TransactionType.SUB</code> will be
    * used and there are no user-defined properties.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    block
    *           The code to execute.
    */
   public static void forBlock(P2JQuery query, 
                               int      direction, 
                               String[] enclosing, 
                               String   label, 
                               Block    block)
   {
      forBlockWorker(TransactionType.SUB, query, direction, enclosing, label, null, null, null, block);
   }
   
   /**
    * Execute a FOR FIRST or FOR LAST block with the given configuration
    * and default properties.  There are no user-defined properties and
    * there are no enclosing non-managed blocks.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    label
    *           The block name of the current block.
    * @param    block
    *           The code to execute.
    */
   public static void forBlock(TransactionType lvl, 
                               P2JQuery        query, 
                               int             direction, 
                               String          label, 
                               Block           block)
   {
      forBlockWorker(lvl, query, direction, null, label, null, null, null, block);
   }
   
   /**
    * Execute a FOR FIRST or FOR LAST block with the given configuration
    * and default properties.  There are no user-defined properties.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    block
    *           The code to execute.
    */
   public static void forBlock(TransactionType lvl,
                               P2JQuery        query, 
                               int             direction,
                               String[]        enclosing,
                               String          label,
                               Block           block)
   {
      forBlockWorker(lvl, query, direction, enclosing, label, null, null, null, block);
   }

   /**
    * Execute a FOR FIRST or FOR LAST block with the given configuration
    * and default properties.  <code>TransactionType.SUB</code> will be used
    * and there are no enclosing non-managed blocks.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    * 
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    label
    *           The block name of the current block.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forBlock(P2JQuery   query, 
                               int        direction, 
                               String     label, 
                               OnPhrase[] on, 
                               Block      block)
   {
      forBlockWorker(TransactionType.SUB, query, direction, null, label, null, null, on, block);
   }
   
   /**
    * Execute a FOR FIRST or FOR LAST block with the given configuration
    * and default properties.  <code>TransactionType.SUB</code> will be used.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    * 
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forBlock(P2JQuery   query, 
                               int        direction, 
                               String[]   enclosing, 
                               String     label, 
                               OnPhrase[] on, 
                               Block      block)
   {
      forBlockWorker(TransactionType.SUB, query, direction, enclosing, label, null, null, on, block);
   }
   
   /**
    * Execute a FOR FIRST or FOR LAST block with the given configuration
    * and default properties. In this case, there are no enclosing
    * non-managed blocks.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    lvl
    *           The transaction level to be honored.
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    label
    *           The block name of the current block.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forBlock(TransactionType lvl,
                               P2JQuery        query,
                               int             direction,
                               String          label,
                               OnPhrase[]      on,
                               Block           block)
   {
      forBlockWorker(lvl, query, direction, null, label, null, null, on, block);
   }
   
   /**                                              
    * Execute a FOR FIRST or FOR LAST block with the given configuration
    * and default properties.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    lvl
    *           The transaction level to be honored.
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.          
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forBlock(TransactionType lvl,
                               P2JQuery        query, 
                               int             direction,
                               String[]        enclosing,
                               String          label,
                               OnPhrase[]      on,
                               Block           block)
   {
      forBlockWorker(lvl, query, direction, enclosing, label, null, null, on, block);
   }
   
   /**
    * Execute a FOR FIRST/LAST WHILE block with the given configuration
    * and default properties. <code>TransactionType.SUB</code> will be
    * used and there are no enclosing non-managed blocks. In addition, there
    * are no user-defined properties.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    * 
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    label
    *           The block name of the current block.
    * @param    expr
    *           The WHILE clause that defines a block condition. This
    *           expression is evaluated before the block body is about to
    *           be entered.  The block body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    block
    *           The code to execute.
    */
   public static void forBlockWhile(P2JQuery  query, 
                                    int       direction,
                                    String    label, 
                                    LogicalOp expr, 
                                    Block     block)
   {
      forBlockWorker(TransactionType.SUB, query, direction, null, label, null, expr, null, block);
   }
   
   /**
    * Execute a FOR FIRST/LAST WHILE block with the given configuration
    * and default properties. <code>TransactionType.SUB</code> will be
    * used and there are no user-defined properties.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    * 
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    expr
    *           The WHILE clause that defines a block condition. This
    *           expression is evaluated before the block body is about to
    *           be entered.  The block body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    block
    *           The code to execute.
    */
   public static void forBlockWhile(P2JQuery query,
                                    int direction,
                                    String[] enclosing, 
                                    String label, 
                                    LogicalOp expr, 
                                    Block block)
   {
      forBlockWorker(TransactionType.SUB, query, direction, enclosing, label, null, expr, null, block);
   }
   
   /**
    * Execute a FOR FIRST/LAST WHILE block with the given configuration
    * and no user-defined or default properties. In addition, there are no
    * enclosing non-managed blocks.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    label
    *           The block name of the current block.
    * @param    expr
    *           The WHILE clause that defines a block condition. This
    *           expression is evaluated before the block body is about to
    *           be entered.  The block body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    block
    *           The code to execute.
    */
   public static void forBlockWhile(TransactionType lvl,
                                    P2JQuery        query,
                                    int             direction,
                                    String          label, 
                                    LogicalOp       expr, 
                                    Block           block)
   {
      forBlockWorker(lvl, query, direction, null, label, null, expr, null, block);
   }
   
   /**
    * Execute a FOR FIRST/LAST WHILE block with the given configuration
    * and no user-defined or default properties.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    expr
    *           The WHILE clause that defines a block condition. This
    *           expression is evaluated before the block body is about to
    *           be entered.  The block body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    block
    *           The code to execute.
    */
   public static void forBlockWhile(TransactionType lvl,
                                    P2JQuery        query,
                                    int             direction,
                                    String[]        enclosing,
                                    String          label,
                                    LogicalOp       expr,
                                    Block           block)
   {
      forBlockWorker(lvl, query, direction, enclosing, label, null, expr, null, block);
   }

   /**
    * Execute a FOR FIRST/LAST WHILE block with the given configuration
    * and default properties. <code>TransactionType.SUB</code> will be
    * used and there are no enclosing non-managed blocks.
    *
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    label
    *           The block name of the current block.
    * @param    expr
    *           The WHILE clause that defines a block condition. This
    *           expression is evaluated before the block body is about to
    *           be entered.  The block body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forBlockWhile(P2JQuery query,
                                    int direction,
                                    String label, 
                                    LogicalOp expr, 
                                    OnPhrase[] on, 
                                    Block block)
   {
      forBlockWorker(TransactionType.SUB, query, direction, null, label, null, expr, on, block);
   }
   
   /**
    * Execute a FOR FIRST/LAST WHILE block with the given configuration
    * and default properties. <code>TransactionType.SUB</code> will be
    * used.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    expr
    *           The WHILE clause that defines a block condition. This
    *           expression is evaluated before the block body is about to
    *           be entered.  The block body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forBlockWhile(P2JQuery   query,
                                    int        direction,
                                    String[]   enclosing,
                                    String     label,
                                    LogicalOp  expr,
                                    OnPhrase[] on,
                                    Block      block)
   {
      forBlockWorker(TransactionType.SUB, query, direction, enclosing, label, null, expr, on, block);
   }
   
   /**
    * Execute a FOR FIRST/LAST WHILE block with the given configuration
    * and default properties. In this case, there are no enclosing
    * non-managed blocks.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    label
    *           The block name of the current block.
    * @param    expr
    *           The WHILE clause that defines a block condition. This
    *           expression is evaluated before the block body is about to
    *           be entered.  The block body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forBlockWhile(TransactionType lvl,
                                    P2JQuery        query,
                                    int             direction,
                                    String          label,
                                    LogicalOp       expr,
                                    OnPhrase[]      on,
                                    Block           block)
   {
      forBlockWorker(lvl, query, direction, null, label, null, expr, on, block);
   }
   
   /**
    * Execute a FOR FIRST/LAST WHILE block with the given configuration
    * and default properties.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    expr      
    *           The WHILE clause that defines a block condition. This
    *           expression is evaluated before the block body is about to
    *           be entered.  The block body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forBlockWhile(TransactionType lvl,
                                    P2JQuery        query,
                                    int             direction,
                                    String[]        enclosing,
                                    String          label,
                                    LogicalOp       expr,
                                    OnPhrase[]      on,
                                    Block           block)
   {
      forBlockWorker(lvl, query, direction, enclosing, label, null, expr, on, block);
   }
             
   /**
    * Execute a FOR FIRST/LAST TO block with the given configuration
    * and default properties. <code>TransactionType.SUB</code> will be
    * used and there are no enclosing non-managed blocks. In addition, there
    * are no user-defined properties.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines the block condition. The block
    *           control variable is initialized before entering the block. 
    *           Before the block body is entered, the control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at that moment). if the termination condition is
    *           met, the block is never entered.
    * @param    block
    *           The code to execute.
    */
   public static void forBlockTo(P2JQuery query, int direction, String label, ToClause to, Block block)
   {
      forBlockWorker(TransactionType.SUB, query, direction, null, label, to, null, null, block);
   }
   
   /**
    * Execute a FOR FIRST/LAST TO block with the given configuration
    * and default properties. <code>TransactionType.SUB</code> will be
    * used and there are no user-defined properties.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines the block condition. The block
    *           control variable is initialized before entering the block. 
    *           Before the block body is entered, the control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at that moment). if the termination condition is
    *           met, the block is never entered.
    * @param    block
    *           The code to execute.
    */
   public static void forBlockTo(P2JQuery query,
                                 int      direction,
                                 String[] enclosing,
                                 String   label,
                                 ToClause to,
                                 Block    block)
   {
      forBlockWorker(TransactionType.SUB, query, direction, enclosing, label, to, null, null, block);
   }
   
   /**
    * Execute a FOR FIRST/LAST TO block with the given configuration
    * and no user-defined or default properties. In addition, there are no
    * enclosing non-managed blocks.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines the block condition. The block
    *           control variable is initialized before entering the block. 
    *           Before the block body is entered, the control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at that moment). if the termination condition is
    *           met, the block is never entered.
    * @param    block
    *           The code to execute.
    */
   public static void forBlockTo(TransactionType lvl,
                                 P2JQuery        query,
                                 int             direction,
                                 String          label,
                                 ToClause        to,
                                 Block           block)
   {
      forBlockWorker(lvl, query, direction, null, label, to, null, null, block);
   }
   
   /**
    * Execute a FOR FIRST/LAST TO block with the given configuration
    * and no user-defined or default properties.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines the block condition. The block
    *           control variable is initialized before entering the block. 
    *           Before the block body is entered, the control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at that moment). if the termination condition is
    *           met, the block is never entered.
    * @param    block
    *           The code to execute.
    */
   public static void forBlockTo(TransactionType lvl,
                                 P2JQuery        query,
                                 int             direction,
                                 String[]        enclosing,
                                 String          label,
                                 ToClause        to,
                                 Block           block)
   {
      forBlockWorker(lvl, query, direction, enclosing, label, to, null, null, block);
   }

   /**
    * Execute a FOR FIRST/LAST TO block with the given configuration
    * and default properties. <code>TransactionType.SUB</code> will be
    * used and there are no enclosing non-managed blocks.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines the block condition. The block
    *           control variable is initialized before entering the block. 
    *           Before the block body is entered, the control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at that moment). if the termination condition is
    *           met, the block is never entered.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forBlockTo(P2JQuery   query,
                                 int        direction,
                                 String     label,
                                 ToClause   to,
                                 OnPhrase[] on,
                                 Block      block)
   {
      forBlockWorker(TransactionType.SUB, query, direction, (String[]) null, label, to, null, on, block);
   }
   
   /**
    * Execute a FOR FIRST/LAST TO block with the given configuration
    * and default properties. <code>TransactionType.SUB</code> will be
    * used.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines the block condition. The block
    *           control variable is initialized before entering the block. 
    *           Before the block body is entered, the control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at that moment). if the termination condition is
    *           met, the block is never entered.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forBlockTo(P2JQuery   query,
                                 int        direction,
                                 String[]   enclosing,
                                 String     label,
                                 ToClause   to,
                                 OnPhrase[] on,
                                 Block      block)
   {
      forBlockWorker(TransactionType.SUB, query, direction, enclosing, label, to, null, on, block);
   }
   
   /**
    * Execute a FOR FIRST/LAST TO block with the given configuration
    * and default properties. In this case, there are no enclosing
    * non-managed blocks.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines the block condition. The block
    *           control variable is initialized before entering the block. 
    *           Before the block body is entered, the control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at that moment). if the termination condition is
    *           met, the block is never entered.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forBlockTo(TransactionType lvl,
                                 P2JQuery        query,
                                 int             direction,
                                 String          label,
                                 ToClause        to,
                                 OnPhrase[]      on,
                                 Block           block)
   {
      forBlockWorker(lvl, query, direction, null, label, to, null, on, block);
   }
   
   /**
    * Execute a FOR FIRST/LAST TO block with the given configuration
    * and default properties.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines the block condition. The block
    *           control variable is initialized before entering the block. 
    *           Before the block body is entered, the control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at that moment). if the termination condition is
    *           met, the block is never entered.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forBlockTo(TransactionType lvl,
                                 P2JQuery        query,
                                 int             direction,
                                 String[]        enclosing,
                                 String          label,
                                 ToClause        to,
                                 OnPhrase[]      on,
                                 Block           block)
   {
      forBlockWorker(lvl, query, direction, enclosing, label, to, null, on, block);
   }
   
   /**
    * Execute a FOR FIRST/LAST WHILE block, FOR FIRST/LAST TO block
    * or FOR FIRST/LAST TO WHILE block with the given configuration and
    * default properties. At least one of the to clause or while expression
    * must be passed and it is valid to have both passed in which case both
    * of the conditions are tested with a logical AND.
    * <p>
    * <code>TransactionType.SUB</code> will be used and there are no
    * enclosing non-managed blocks. In addition, there are no user-defined
    * properties.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines the block condition. The block
    *           control variable is initialized before entering the block. 
    *           Before the block body is entered, the control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at that moment). if the termination condition is
    *           met, the block is never entered.
    * @param    expr      
    *           The WHILE clause that defines a block condition. This
    *           expression is evaluated before the block body is about to
    *           be entered.  The block body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    block
    *           The code to execute.
    */
   public static void forBlockToWhile(P2JQuery  query, 
                                      int       direction, 
                                      String    label, 
                                      ToClause  to, 
                                      LogicalOp expr, 
                                      Block     block)
   {
      forBlockWorker(TransactionType.SUB, query, direction, null, label, to, expr, null, block);
   }
   
   /**
    * Execute a FOR FIRST/LAST WHILE block, FOR FIRST/LAST TO block
    * or FOR FIRST/LAST TO WHILE block with the given configuration and
    * default properties. At least one of the to clause or while expression
    * must be passed and it is valid to have both passed in which case both
    * of the conditions are tested with a logical AND.
    * <p>
    * <code>TransactionType.SUB</code> will be used and there are no
    * user-defined properties.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines the block condition. The block
    *           control variable is initialized before entering the block. 
    *           Before the block body is entered, the control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at that moment). if the termination condition is
    *           met, the block is never entered.
    * @param    expr      
    *           The WHILE clause that defines a block condition. This
    *           expression is evaluated before the block body is about to
    *           be entered.  The block body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    block
    *           The code to execute.
    */
   public static void forBlockToWhile(P2JQuery  query,
                                      int       direction,
                                      String[]  enclosing,
                                      String    label,
                                      ToClause  to,
                                      LogicalOp expr,
                                      Block     block)
   {
      forBlockWorker(TransactionType.SUB, query, direction, enclosing, label, to, expr, null, block);
   }
   
   /**
    * Execute a FOR FIRST/LAST WHILE block, FOR FIRST/LAST TO block
    * or FOR FIRST/LAST TO WHILE block with the given configuration and
    * default properties. At least one of the to clause or while expression
    * must be passed and it is valid to have both passed in which case both
    * of the conditions are tested with a logical AND.
    * <p>
    * There are no user-defined properties and no enclosing non-managed
    * blocks.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines the block condition. The block
    *           control variable is initialized before entering the block. 
    *           Before the block body is entered, the control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at that moment). if the termination condition is
    *           met, the block is never entered.
    * @param    expr      
    *           The WHILE clause that defines a block condition. This
    *           expression is evaluated before the block body is about to
    *           be entered.  The block body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    block
    *           The code to execute.
    */
   public static void forBlockToWhile(TransactionType lvl,
                                      P2JQuery        query,
                                      int             direction,
                                      String          label,
                                      ToClause        to,
                                      LogicalOp       expr,
                                      Block           block)
   {
      forBlockWorker(lvl, query, direction, null, label, to, expr, null, block);
   }
   
   /**
    * Execute a FOR FIRST/LAST WHILE block, FOR FIRST/LAST TO block
    * or FOR FIRST/LAST TO WHILE block with the given configuration and
    * default properties. At least one of the to clause or while expression
    * must be passed and it is valid to have both passed in which case both
    * of the conditions are tested with a logical AND.
    * <p>
    * There are no user-defined properties.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines the block condition. The block
    *           control variable is initialized before entering the block. 
    *           Before the block body is entered, the control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at that moment). if the termination condition is
    *           met, the block is never entered.
    * @param    expr      
    *           The WHILE clause that defines a block condition. This
    *           expression is evaluated before the block body is about to
    *           be entered.  The block body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    block
    *           The code to execute.
    */
   public static void forBlockToWhile(TransactionType lvl,
                                      P2JQuery        query,
                                      int             direction,
                                      String[]        enclosing,
                                      String          label,
                                      ToClause        to,
                                      LogicalOp       expr,
                                      Block           block)
   {
      forBlockWorker(lvl, query, direction, enclosing, label, to, expr, null, block);
   }

   /**
    * Execute a FOR FIRST/LAST WHILE block, FOR FIRST/LAST TO block
    * or FOR FIRST/LAST TO WHILE block with the given configuration and
    * default properties. At least one of the to clause or while expression
    * must be passed and it is valid to have both passed in which case both
    * of the conditions are tested with a logical AND.
    * <p>
    * <code>TransactionType.SUB</code> will be used and there are no
    * enclosing non-managed blocks.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines the block condition. The block
    *           control variable is initialized before entering the block. 
    *           Before the block body is entered, the control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at that moment). if the termination condition is
    *           met, the block is never entered.
    * @param    expr      
    *           The WHILE clause that defines a block condition. This
    *           expression is evaluated before the block body is about to
    *           be entered.  The block body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forBlockToWhile(P2JQuery   query,
                                      int        direction,
                                      String     label,
                                      ToClause   to,
                                      LogicalOp  expr,
                                      OnPhrase[] on,
                                      Block      block)
   {
      forBlockWorker(TransactionType.SUB, query, direction, (String[]) null, label, to, expr, on, block);
   }
   
   /**
    * Execute a FOR FIRST/LAST WHILE block, FOR FIRST/LAST TO block
    * or FOR FIRST/LAST TO WHILE block with the given configuration and
    * default properties. At least one of the to clause or while expression
    * must be passed and it is valid to have both passed in which case both
    * of the conditions are tested with a logical AND.
    * <p>
    * <code>TransactionType.SUB</code> will be used.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines the block condition. The block
    *           control variable is initialized before entering the block. 
    *           Before the block body is entered, the control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at that moment). if the termination condition is
    *           met, the block is never entered.
    * @param    expr      
    *           The WHILE clause that defines a block condition. This
    *           expression is evaluated before the block body is about to
    *           be entered.  The block body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forBlockToWhile(P2JQuery   query,
                                      int        direction,
                                      String[]   enclosing,
                                      String     label,
                                      ToClause   to,
                                      LogicalOp  expr,
                                      OnPhrase[] on,
                                      Block      block)
   {
      forBlockWorker(TransactionType.SUB, query, direction, enclosing, label, to, expr, on, block);
   }
   
   /**
    * Execute a FOR FIRST/LAST WHILE block, FOR FIRST/LAST TO block
    * or FOR FIRST/LAST TO WHILE block with the given configuration and
    * default properties.  At least one of the to clause or while expression
    * must be passed and it is valid to have both passed in which case both
    * of the conditions are tested with a logical AND.
    * <p>
    * There are no enclosing non-managed blocks.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines the block condition. The block
    *           control variable is initialized before entering the block. 
    *           Before the block body is entered, the control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at that moment). if the termination condition is
    *           met, the block is never entered.
    * @param    expr      
    *           The WHILE clause that defines a block condition. This
    *           expression is evaluated before the block body is about to
    *           be entered.  The block body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forBlockToWhile(TransactionType lvl,
                                      P2JQuery        query,
                                      int             direction,
                                      String          label,
                                      ToClause        to,
                                      LogicalOp       expr,
                                      OnPhrase[]      on,
                                      Block           block)
   {
      forBlockWorker(lvl, query, direction, null, label, to, expr, on, block);
   }
   
   /**
    * Execute a FOR FIRST/LAST WHILE block, FOR FIRST/LAST TO block
    * or FOR FIRST/LAST TO WHILE block with the given configuration and
    * default properties.  At least one of the to clause or while expression
    * must be passed and it is valid to have both passed in which case both
    * of the conditions are tested with a logical AND.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines the block condition. The block
    *           control variable is initialized before entering the block. 
    *           Before the block body is entered, the control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at that moment). if the termination condition is
    *           met, the block is never entered.
    * @param    expr      
    *           The WHILE clause that defines a block condition. This
    *           expression is evaluated before the block body is about to
    *           be entered.  The block body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forBlockToWhile(TransactionType lvl,
                                      P2JQuery        query,
                                      int             direction,
                                      String[]        enclosing,
                                      String          label,
                                      ToClause        to,
                                      LogicalOp       expr,
                                      OnPhrase[]      on,
                                      Block           block)
   {
      forBlockWorker(lvl, query, direction, enclosing, label, to, expr, on, block);
   }
             
   /**
    * Execute a FOR EACH loop with the given configuration
    * and default properties. <code>TransactionType.SUB</code> will be
    * used and there are no enclosing non-managed blocks. In addition, there
    * are no user-defined properties.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    query
    *           query that will iterate forBlock.
    * @param    label
    *           The block name of the current block.
    * @param    block
    *           The code to execute.
    */
   public static void forEach(P2JQuery query, String label, Block block)
   {
      forEachWorker(TransactionType.SUB, query, null, label, null, null, null, block);
   }
   
   /**
    * Execute a FOR EACH loop with the given configuration
    * and default properties. <code>TransactionType.SUB</code> will be
    * used and there are no user-defined properties.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    query
    *           query that will iterate forEachBlock.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    block
    *           The code to execute.
    */
   public static void forEach(P2JQuery query, String[] enclosing, String label, Block block)
   {
      forEachWorker(TransactionType.SUB, query, enclosing, label, null, null, null, block);
   }
   
   /**
    * Execute a FOR EACH loop with the given configuration
    * and default properties.  There are no user-defined properties and
    * there are no enclosing non-managed blocks.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    query
    *           query that will iterate forEachBlock.
    * @param    label
    *           The block name of the current block.
    * @param    block
    *           The code to execute.
    */
   public static void forEach(TransactionType lvl, P2JQuery query, String label, Block block)
   {
      forEachWorker(lvl, query, null, label, null, null, null, block);
   }
   
   /**
    * Execute a FOR EACH loop with the given configuration
    * and default properties.  There are no user-defined properties.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    query
    *           query that will iterate forEachBlock.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    block
    *           The code to execute.
    */
   public static void forEach(TransactionType lvl,
                              P2JQuery        query,
                              String[]        enclosing,
                              String          label,
                              Block           block)
   {
      forEachWorker(lvl, query, enclosing, label, null, null, null, block);
   }

   /**
    * Execute a FOR EACH loop with the given configuration
    * and default properties.  <code>TransactionType.SUB</code> will be used
    * and there are no enclosing non-managed blocks.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    query
    *           query that will iterate forEachBlock.
    * @param    label
    *           The block name of the current block.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forEach(P2JQuery query, String label, OnPhrase[] on, Block block)
   {
      forEachWorker(TransactionType.SUB, query, null, label, null, null, on, block);
   }
   
   /**
    * Execute a FOR EACH loop with the given configuration
    * and default properties.  <code>TransactionType.SUB</code> will be used.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    query
    *           query that will iterate forEachBlock.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forEach(P2JQuery   query,
                              String[]   enclosing,
                              String     label,
                              OnPhrase[] on,
                              Block      block)
   {
      forEachWorker(TransactionType.SUB, query, enclosing, label, null, null, on, block);
   }
   
   /**
    * Execute a FOR EACH loop with the given configuration
    * and default properties. In this case, there are no enclosing
    * non-managed blocks.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    query
    *           query that will iterate forEachBlock.
    * @param    label
    *           The block name of the current block.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forEach(TransactionType lvl,
                              P2JQuery        query,
                              String          label,
                              OnPhrase[]      on,
                              Block           block)
   {
      forEachWorker(lvl, query, null, label, null, null, on, block);
   }
   
   /**                                              
    * Execute a FOR EACH loop with the given configuration
    * and default properties.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    lvl
    *           The transaction level to be honored.
    * @param    query
    *           query that will iterate forEachBlock.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forEach(TransactionType lvl,
                              P2JQuery        query,
                              String[]        enclosing,
                              String          label,
                              OnPhrase[]      on,
                              Block           block)
   {
      forEachWorker(lvl, query, enclosing, label, null, null, on, block);
   }
   
   /**
    * Execute a FOR EACH WHILE block with the given configuration
    * and default properties. <code>TransactionType.SUB</code> will be
    * used and there are no enclosing non-managed blocks. In addition, there
    * are no user-defined properties.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    query
    *           query that will iterate forEachBlock.
    * @param    label
    *           The block name of the current block.
    * @param    expr
    *           The WHILE clause that defines the loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    block
    *           The code to execute.
    */
   public static void forEachWhile(P2JQuery query, String label, LogicalOp expr, Block block)
   {
      forEachWorker(TransactionType.SUB, query, null, label, null, expr, null, block);
   }
   
   /**
    * Execute a FOR EACH WHILE block with the given configuration
    * and default properties. <code>TransactionType.SUB</code> will be
    * used and there are no user-defined properties.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    query
    *           query that will iterate forEachBlock.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    expr
    *           The WHILE clause that defines the loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    block
    *           The code to execute.
    */
   public static void forEachWhile(P2JQuery query, 
                                   String[] enclosing, 
                                   String label, 
                                   LogicalOp expr, 
                                   Block block)
   {
      forEachWorker(TransactionType.SUB, query, enclosing, label, null, expr, null, block);
   }
   
   /**
    * Execute a FOR EACH WHILE block with the given configuration
    * and no user-defined or default properties. In addition, there are no
    * enclosing non-managed blocks.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    query
    *           query that will iterate forEachBlock.
    * @param    label
    *           The block name of the current block.
    * @param    expr
    *           The WHILE clause that defines the loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    block
    *           The code to execute.
    */
   public static void forEachWhile(TransactionType lvl,
                                   P2JQuery        query,
                                   String          label,
                                   LogicalOp       expr,
                                   Block           block)
   {
      forEachWorker(lvl, query, null, label, null, expr, null, block);
   }
   
   /**
    * Execute a FOR EACH WHILE block with the given configuration
    * and no user-defined or default properties.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    query
    *           query that will iterate forEachBlock.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    expr
    *           The WHILE clause that defines the loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    block
    *           The code to execute.
    */
   public static void forEachWhile(TransactionType lvl,
                                   P2JQuery        query,
                                   String[]        enclosing,
                                   String          label,
                                   LogicalOp       expr,
                                   Block           block)
   {
      forEachWorker(lvl, query, enclosing, label, null, expr, null, block);
   }

   /**
    * Execute a FOR EACH WHILE block with the given configuration
    * and default properties. <code>TransactionType.SUB</code> will be
    * used and there are no enclosing non-managed blocks.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    query
    *           query that will iterate forEachBlock.
    * @param    label
    *           The block name of the current block.
    * @param    expr
    *           The WHILE clause that defines the loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forEachWhile(P2JQuery query, String label, LogicalOp expr, OnPhrase[] on, Block block)
   {
      forEachWorker(TransactionType.SUB, query, null, label, null, expr, on, block);
   }
   
   /**
    * Execute a FOR EACH WHILE block with the given configuration
    * and default properties. <code>TransactionType.SUB</code> will be
    * used.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    query
    *           query that will iterate forEachBlock.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    expr
    *           The WHILE clause that defines the loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forEachWhile(P2JQuery   query,
                                   String[]   enclosing,
                                   String     label,
                                   LogicalOp  expr,
                                   OnPhrase[] on,
                                   Block      block)
   {
      forEachWorker(TransactionType.SUB, query, enclosing, label, null, expr, on, block);
   }
   
   /**
    * Execute a FOR EACH WHILE block with the given configuration
    * and default properties. In this case, there are no enclosing
    * non-managed blocks.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    query
    *           query that will iterate forEachBlock.
    * @param    label
    *           The block name of the current block.
    * @param    expr
    *           The WHILE clause that defines the loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forEachWhile(TransactionType lvl,
                                   P2JQuery        query,
                                   String          label,
                                   LogicalOp       expr,
                                   OnPhrase[]      on,
                                   Block           block)
   {
      forEachWorker(lvl, query, null, label, null, expr, on, block);
   }
   
   /**
    * Execute a FOR EACH WHILE block with the given configuration
    * and default properties.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    query
    *           query that will iterate forEachBlock.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    expr      
    *           The WHILE clause that defines the loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forEachWhile(TransactionType lvl,
                                   P2JQuery        query,
                                   String[]        enclosing,
                                   String          label,
                                   LogicalOp       expr,
                                   OnPhrase[]      on,
                                   Block           block)
   {
      forEachWorker(lvl, query, enclosing, label, null, expr, on, block);
   }
             
   /**
    * Execute a FOR EACH TO block with the given configuration
    * and default properties. <code>TransactionType.SUB</code> will be
    * used and there are no enclosing non-managed blocks. In addition, there
    * are no user-defined properties.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    query
    *           query that will iterate forEachBlock.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    block
    *           The code to execute.
    */
   public static void forEachTo(P2JQuery query,
                                String   label,
                                ToClause to,
                                Block    block)
   {
      forEachWorker(TransactionType.SUB, query, null, label, to, null, null, block);
   }
   
   /**
    * Execute a FOR EACH TO block with the given configuration
    * and default properties. <code>TransactionType.SUB</code> will be
    * used and there are no user-defined properties.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    query
    *           query that will iterate forEachBlock.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    block
    *           The code to execute.
    */
   public static void forEachTo(P2JQuery query,
                                String[] enclosing,
                                String   label,
                                ToClause to,
                                Block    block)
   {
      forEachWorker(TransactionType.SUB, query, enclosing, label, to, null, null, block);
   }
   
   /**
    * Execute a FOR EACH TO block with the given configuration
    * and no user-defined or default properties. In addition, there are no
    * enclosing non-managed blocks.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    query
    *           query that will iterate forEachBlock.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    block
    *           The code to execute.
    */
   public static void forEachTo(TransactionType lvl,
                                P2JQuery        query,
                                String          label,
                                ToClause        to,
                                Block           block)
   {
      forEachWorker(lvl, query, null, label, to, null, null, block);
   }
   
   /**
    * Execute a FOR EACH TO block with the given configuration
    * and no user-defined or default properties.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    query
    *           query that will iterate forEachBlock.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    block
    *           The code to execute.
    */
   public static void forEachTo(TransactionType lvl,
                                P2JQuery        query,
                                String[]        enclosing,
                                String          label,
                                ToClause        to,
                                Block           block)
   {
      forEachWorker(lvl, query, enclosing, label, to, null, null, block);
   }

   /**
    * Execute a FOR EACH TO block with the given configuration
    * and default properties. <code>TransactionType.SUB</code> will be
    * used and there are no enclosing non-managed blocks.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    query
    *           query that will iterate forEachBlock.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forEachTo(P2JQuery   query,
                                String     label,
                                ToClause   to,
                                OnPhrase[] on,
                                Block      block)
   {
      forEachWorker(TransactionType.SUB, query, (String[]) null, label, to, null, on, block);
   }
   
   /**
    * Execute a FOR EACH TO block with the given configuration
    * and default properties. <code>TransactionType.SUB</code> will be
    * used.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    query
    *           query that will iterate forEachBlock.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forEachTo(P2JQuery   query,
                                String[]   enclosing,
                                String     label,
                                ToClause   to,
                                OnPhrase[] on,
                                Block      block)
   {
      forEachWorker(TransactionType.SUB, query, enclosing, label, to, null, on, block);
   }
   
   /**
    * Execute a FOR EACH TO block with the given configuration
    * and default properties. In this case, there are no enclosing
    * non-managed blocks.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    query
    *           query that will iterate forEachBlock.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forEachTo(TransactionType lvl,
                                P2JQuery        query,
                                String          label,
                                ToClause        to,
                                OnPhrase[]      on,
                                Block           block)
   {
      forEachWorker(lvl, query, null, label, to, null, on, block);
   }
   
   /**
    * Execute a FOR EACH TO block with the given configuration
    * and default properties.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    query
    *           query that will iterate forEachBlock.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forEachTo(TransactionType lvl,
                                P2JQuery        query,
                                String[]        enclosing,
                                String          label,
                                ToClause        to,
                                OnPhrase[]      on,
                                Block           block)
   {
      forEachWorker(lvl, query, enclosing, label, to, null, on, block);
   }
   
   /**
    * Execute a FOR EACH WHILE block, FOR EACH TO block
    * or FOR EACH TO WHILE block with the given configuration and
    * default properties. At least one of the to clause or while expression
    * must be passed and it is valid to have both passed in which case both
    * of the conditions are tested with a logical AND.
    * <p>
    * <code>TransactionType.SUB</code> will be used and there are no
    * enclosing non-managed blocks. In addition, there are no user-defined
    * properties.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    query
    *           query that will iterate forEachBlock.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    expr      
    *           The WHILE clause that defines a loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    block
    *           The code to execute.
    */
   public static void forEachToWhile(P2JQuery query, String label, ToClause to, LogicalOp expr, Block block)
   {
      forEachWorker(TransactionType.SUB, query, null, label, to, expr, null, block);
   }
   
   /**
    * Execute a FOR EACH WHILE block, FOR EACH TO block
    * or FOR EACH TO WHILE block with the given configuration and
    * default properties. At least one of the to clause or while expression
    * must be passed and it is valid to have both passed in which case both
    * of the conditions are tested with a logical AND.
    * <p>
    * <code>TransactionType.SUB</code> will be used and there are no
    * user-defined properties.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    query
    *           query that will iterate forEachBlock.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    expr      
    *           The WHILE clause that defines a loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    block
    *           The code to execute.
    */
   public static void forEachToWhile(P2JQuery  query,
                                     String[]  enclosing,
                                     String    label,
                                     ToClause  to,
                                     LogicalOp expr,
                                     Block     block)
   {
      forEachWorker(TransactionType.SUB, query, enclosing, label, to, expr, null, block);
   }
   
   /**
    * Execute a FOR EACH WHILE block, FOR EACH TO block
    * or FOR EACH TO WHILE block with the given configuration and
    * default properties. At least one of the to clause or while expression
    * must be passed and it is valid to have both passed in which case both
    * of the conditions are tested with a logical AND.
    * <p>
    * There are no user-defined properties and no enclosing non-managed
    * blocks.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    query
    *           query that will iterate forEachBlock.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    expr      
    *           The WHILE clause that defines a loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    block
    *           The code to execute.
    */
   public static void forEachToWhile(TransactionType lvl,
                                     P2JQuery        query,
                                     String          label,
                                     ToClause        to,
                                     LogicalOp       expr,
                                     Block           block)
   {
      forEachWorker(lvl, query, null, label, to, expr, null, block);
   }
   
   /**
    * Execute a FOR EACH WHILE block, FOR EACH TO block
    * or FOR EACH TO WHILE block with the given configuration and
    * default properties. At least one of the to clause or while expression
    * must be passed and it is valid to have both passed in which case both
    * of the conditions are tested with a logical AND.
    * <p>
    * There are no user-defined properties.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    query
    *           query that will iterate forEachBlock.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    expr      
    *           The WHILE clause that defines a loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    block
    *           The code to execute.
    */
   public static void forEachToWhile(TransactionType lvl,
                                     P2JQuery        query,
                                     String[]        enclosing,
                                     String          label,
                                     ToClause        to,
                                     LogicalOp       expr,
                                     Block           block)
   {
      forEachWorker(lvl, query, enclosing, label, to, expr, null, block);
   }

   /**
    * Execute a FOR EACH WHILE block, FOR EACH TO block
    * or FOR EACH TO WHILE block with the given configuration and
    * default properties. At least one of the to clause or while expression
    * must be passed and it is valid to have both passed in which case both
    * of the conditions are tested with a logical AND.
    * <p>
    * <code>TransactionType.SUB</code> will be used and there are no
    * enclosing non-managed blocks.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    query
    *           query that will iterate forEachBlock.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    expr      
    *           The WHILE clause that defines a loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forEachToWhile(P2JQuery   query,
                                     String     label,
                                     ToClause   to,
                                     LogicalOp  expr,
                                     OnPhrase[] on,
                                     Block      block)
   {
      forEachWorker(TransactionType.SUB, query, (String[]) null, label, to, expr, on, block);
   }
   
   /**
    * Execute a FOR EACH WHILE block, FOR EACH TO block
    * or FOR EACH TO WHILE block with the given configuration and
    * default properties. At least one of the to clause or while expression
    * must be passed and it is valid to have both passed in which case both
    * of the conditions are tested with a logical AND.
    * <p>
    * <code>TransactionType.SUB</code> will be used.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    query
    *           query that will iterate forEachBlock.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    expr      
    *           The WHILE clause that defines a loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forEachToWhile(P2JQuery   query,
                                     String[]   enclosing,
                                     String     label,
                                     ToClause   to,
                                     LogicalOp  expr,
                                     OnPhrase[] on,
                                     Block      block)
   {
      forEachWorker(TransactionType.SUB, query, enclosing, label, to, expr, on, block);
   }
   
   /**
    * Execute a FOR EACH WHILE block, FOR EACH TO block
    * or FOR EACH TO WHILE block with the given configuration and
    * default properties.  At least one of the to clause or while expression
    * must be passed and it is valid to have both passed in which case both
    * of the conditions are tested with a logical AND.
    * <p>
    * There are no enclosing non-managed blocks.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    query
    *           query that will iterate forEachBlock.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    expr      
    *           The WHILE clause that defines a loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forEachToWhile(TransactionType lvl,
                                     P2JQuery        query,
                                     String          label,
                                     ToClause        to,
                                     LogicalOp       expr,
                                     OnPhrase[]      on,
                                     Block           block)
   {
      forEachWorker(lvl, query, null, label, to, expr, on, block);
   }
   
   /**
    * Execute a FOR EACH WHILE block, FOR EACH TO block
    * or FOR EACH TO WHILE block with the given configuration and
    * default properties.  At least one of the to clause or while expression
    * must be passed and it is valid to have both passed in which case both
    * of the conditions are tested with a logical AND.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself.  This
    * means that the caller is responsible for all query processing. The
    * record retrieval must be done on the first line of code in the block
    * to duplicate the Progress behavior. Note that this is required to
    * handle all error cases and 4GL conditions properly.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    query
    *           query that will iterate forEachBlock.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    expr      
    *           The WHILE clause that defines a loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   public static void forEachToWhile(TransactionType lvl,
                                     P2JQuery        query,
                                     String[]        enclosing,
                                     String          label,
                                     ToClause        to,
                                     LogicalOp       expr,
                                     OnPhrase[]      on,
                                     Block           block)
   {
      forEachWorker(lvl, query, enclosing, label, to, expr, on, block);
   }
             
   /**
    * Execute the given editing block for the given frame and widget list
    * with <code>PROMPT-FOR</code> semanics. All looping, sub-transaction
    * properties and block properties will be honored.
    *
    * @param    frame
    *           The frame for which the editing block is associated.
    * @param    widgets
    *           The widgets in the given frame that are to be enabled for
    *           editing.
    * @param    label
    *           The label of the block for use in control flow statements
    *           such as <code>LEAVE</code> or <code>NEXT</code>.
    * @param    block
    *           The code for the editing block body.
    */
   public static void promptForEditingUnlessHidden(CommonFrame    frame,
                                                   FrameElement[] widgets,
                                                   String         label,
                                                   Block          block)
   {
      FrameElement[] dataChanged = GenericFrame.removeHiddenWidgets(widgets);
      
      if (dataChanged == null || dataChanged.length == 0)
      {
         return;
      }
      
      editingBlock(frame, dataChanged, null,  null, label, block, CommonFrame.PROMPT_FOR);
   }
   
   /**
    * Execute the given editing block for the given frame and widget list
    * with <code>PROMPT-FOR</code> semanics. All looping, sub-transaction
    * properties and block properties will be honored.
    *
    * @param    frame
    *           The frame for which the editing block is associated.
    * @param    widgets
    *           The widgets in the given frame that are to be enabled for
    *           editing.
    * @param    enclosing
    *           The list of enclosing blocks of which this class is unaware.
    *           Any LEAVE or NEXT that references one of those enclosing
    *           blocks must not unwind the stack further using an exception,
    *           but rather it must return and let the caller check to see if
    *           a deferred LEAVE or NEXT must be honored.
    * @param    label
    *           The label of the block for use in control flow statements
    *           such as <code>LEAVE</code> or <code>NEXT</code>.
    * @param    block
    *           The code for the editing block body.
    */
   public static void promptForEditingUnlessHidden(CommonFrame    frame,
                                                   FrameElement[] widgets,
                                                   String[]       enclosing,
                                                   String         label,
                                                   Block          block)
   {
      FrameElement[] dataChanged = GenericFrame.removeHiddenWidgets(widgets);
      
      if (dataChanged == null || dataChanged.length == 0)
      {
         return;
      }
      editingBlock(frame, dataChanged, null, enclosing, label, block, CommonFrame.PROMPT_FOR);
   }
   
   /**
    * Execute the given editing block for the given frame and widget list
    * with <code>PROMPT-FOR</code> semanics. All looping, sub-transaction
    * properties and block properties will be honored.  The exit from the
    * editing block will be based on the given <code>GO-ON</code> event list.
    *
    * @param    frame
    *           The frame for which the editing block is associated.
    * @param    widgets
    *           The widgets in the given frame that are to be enabled for
    *           editing.
    * @param    goOn
    *           The exit conditions for this loop.
    * @param    label
    *           The label of the block for use in control flow statements
    *           such as <code>LEAVE</code> or <code>NEXT</code>.
    * @param    block
    *           The code for the editing block body.
    */
   public static void promptForEditingUnlessHidden(CommonFrame    frame,
                                                   FrameElement[] widgets,
                                                   EventList      goOn,
                                                   String         label,
                                                   Block          block)
   {
      FrameElement[] dataChanged = GenericFrame.removeHiddenWidgets(widgets);
      
      if (dataChanged == null || dataChanged.length == 0)
      {
         return;
      }

      editingBlock(frame, dataChanged, goOn, null, label, block, CommonFrame.PROMPT_FOR);
   }
   
   /**
    * Execute the given editing block for the given frame and widget list
    * with <code>PROMPT-FOR</code> semanics. All looping, sub-transaction
    * properties and block properties will be honored.  The exit from the
    * editing block will be based on the given <code>GO-ON</code> event list.
    *
    * @param    frame
    *           The frame for which the editing block is associated.
    * @param    widgets
    *           The widgets in the given frame that are to be enabled for
    *           editing.
    * @param    goOn
    *           The exit conditions for this loop.
    * @param    enclosing
    *           The list of enclosing blocks of which this class is unaware.
    *           Any LEAVE or NEXT that references one of those enclosing
    *           blocks must not unwind the stack further using an exception,
    *           but rather it must return and let the caller check to see if
    *           a deferred LEAVE or NEXT must be honored.
    * @param    label
    *           The label of the block for use in control flow statements
    *           such as <code>LEAVE</code> or <code>NEXT</code>.
    * @param    block
    *           The code for the editing block body.
    */
   public static void promptForEditingUnlessHidden(CommonFrame    frame,
                                                   FrameElement[] widgets,
                                                   EventList      goOn,
                                                   String[]       enclosing,
                                                   String         label,
                                                   Block          block)
   {
      FrameElement[] dataChanged = GenericFrame.removeHiddenWidgets(widgets);
      
      if (dataChanged == null || dataChanged.length == 0)
      {
         return;
      }

      editingBlock(frame, dataChanged, goOn, enclosing, label, block, CommonFrame.PROMPT_FOR);
   }
   
   /**
    * Execute the given editing block for the given frame and widget list
    * with <code>SET</code> semanics. All looping, sub-transaction
    * properties and block properties will be honored.
    *
    * @param    frame
    *           The frame for which the editing block is associated.
    * @param    widgets
    *           The widgets in the given frame that are to be enabled for
    *           editing.
    * @param    label
    *           The label of the block for use in control flow statements
    *           such as <code>LEAVE</code> or <code>NEXT</code>.
    * @param    block
    *           The code for the editing block body.
    */
   public static void setEditingUnlessHidden(CommonFrame    frame,
                                             FrameElement[] widgets,
                                             String         label,
                                             Block          block)
   {
      FrameElement[] dataChanged = GenericFrame.removeHiddenWidgets(widgets);
      
      if (dataChanged == null || dataChanged.length == 0)
      {
         return;
      }

      editingBlock(frame, dataChanged, null, null, label, block, CommonFrame.SET);
   }
   
   /**
    * Execute the given editing block for the given frame and widget list
    * with <code>SET</code> semanics. All looping, sub-transaction
    * properties and block properties will be honored.
    *
    * @param    frame
    *           The frame for which the editing block is associated.
    * @param    widgets
    *           The widgets in the given frame that are to be enabled for
    *           editing.
    * @param    enclosing
    *           The list of enclosing blocks of which this class is unaware.
    *           Any LEAVE or NEXT that references one of those enclosing
    *           blocks must not unwind the stack further using an exception,
    *           but rather it must return and let the caller check to see if
    *           a deferred LEAVE or NEXT must be honored.
    * @param    label
    *           The label of the block for use in control flow statements
    *           such as <code>LEAVE</code> or <code>NEXT</code>.
    * @param    block
    *           The code for the editing block body.
    */
   public static void setEditingUnlessHidden(CommonFrame    frame,
                                             FrameElement[] widgets,
                                             String[]       enclosing,
                                             String         label,
                                             Block          block)
   {
      FrameElement[] dataChanged = GenericFrame.removeHiddenWidgets(widgets);
      
      if (dataChanged == null || dataChanged.length == 0)
      {
         return;
      }

      editingBlock(frame, dataChanged, null, enclosing, label, block, CommonFrame.SET);
   }
   
   /**
    * Execute the given editing block for the given frame and widget list
    * with <code>SET</code> semanics. All looping, sub-transaction
    * properties and block properties will be honored.  The exit from the
    * editing block will be based on the given <code>GO-ON</code> event list.
    *
    * @param    frame
    *           The frame for which the editing block is associated.
    * @param    widgets
    *           The widgets in the given frame that are to be enabled for
    *           editing.
    * @param    goOn
    *           The exit conditions for this loop.
    * @param    label
    *           The label of the block for use in control flow statements
    *           such as <code>LEAVE</code> or <code>NEXT</code>.
    * @param    block
    *           The code for the editing block body.
    */
   public static void setEditingUnlessHidden(CommonFrame    frame,
                                             FrameElement[] widgets,
                                             EventList      goOn,
                                             String         label,
                                             Block          block)
   {
      FrameElement[] dataChanged = GenericFrame.removeHiddenWidgets(widgets);
      
      if (dataChanged == null || dataChanged.length == 0)
      {
         return;
      }

      editingBlock(frame, dataChanged, goOn, null, label, block, CommonFrame.SET);
   }
   
   /**
    * Execute the given editing block for the given frame and widget list
    * with <code>SET</code> semanics. All looping, sub-transaction
    * properties and block properties will be honored.  The exit from the
    * editing block will be based on the given <code>GO-ON</code> event list.
    *
    * @param    frame
    *           The frame for which the editing block is associated.
    * @param    widgets
    *           The widgets in the given frame that are to be enabled for
    *           editing.
    * @param    goOn
    *           The exit conditions for this loop.
    * @param    enclosing
    *           The list of enclosing blocks of which this class is unaware.
    *           Any LEAVE or NEXT that references one of those enclosing
    *           blocks must not unwind the stack further using an exception,
    *           but rather it must return and let the caller check to see if
    *           a deferred LEAVE or NEXT must be honored.
    * @param    label
    *           The label of the block for use in control flow statements
    *           such as <code>LEAVE</code> or <code>NEXT</code>.
    * @param    block
    *           The code for the editing block body.
    */
   public static void setEditingUnlessHidden(CommonFrame    frame,
                                             FrameElement[] widgets,
                                             EventList      goOn,
                                             String[]       enclosing,
                                             String         label,
                                             Block          block)
   {
      FrameElement[] dataChanged = GenericFrame.removeHiddenWidgets(widgets);
      
      if (dataChanged == null || dataChanged.length == 0)
      {
         return;
      }

      editingBlock(frame, dataChanged, goOn, enclosing, label, block, CommonFrame.SET);
   }
   
   /**
    * Execute the given editing block for the given frame and widget list
    * with <code>UPDATE</code> semanics. All looping, sub-transaction
    * properties and block properties will be honored.
    *
    * @param    frame
    *           The frame for which the editing block is associated.
    * @param    widgets
    *           The widgets in the given frame that are to be enabled for
    *           editing.
    * @param    label
    *           The label of the block for use in control flow statements
    *           such as <code>LEAVE</code> or <code>NEXT</code>.
    * @param    block
    *           The code for the editing block body.
    */
   public static void updateEditingUnlessHidden(CommonFrame    frame,
                                                FrameElement[] widgets,
                                                String         label,
                                                Block          block)
   {
      FrameElement[] dataChanged = GenericFrame.removeHiddenWidgets(widgets);
      
      if (dataChanged == null || dataChanged.length == 0)
      {
         return;
      }

      editingBlock(frame, dataChanged, null, null, label, block, CommonFrame.UPDATE);
   }
   
   /**
    * Execute the given editing block for the given frame and widget list
    * with <code>UPDATE</code> semanics. All looping, sub-transaction
    * properties and block properties will be honored.
    *
    * @param    frame
    *           The frame for which the editing block is associated.
    * @param    widgets
    *           The widgets in the given frame that are to be enabled for
    *           editing.
    * @param    enclosing
    *           The list of enclosing blocks of which this class is unaware.
    *           Any LEAVE or NEXT that references one of those enclosing
    *           blocks must not unwind the stack further using an exception,
    *           but rather it must return and let the caller check to see if
    *           a deferred LEAVE or NEXT must be honored.
    * @param    label
    *           The label of the block for use in control flow statements
    *           such as <code>LEAVE</code> or <code>NEXT</code>.
    * @param    block
    *           The code for the editing block body.
    */
   public static void updateEditingUnlessHidden(CommonFrame    frame,
                                                FrameElement[] widgets,
                                                String[]       enclosing,
                                                String         label,
                                                Block          block)
   {
      FrameElement[] dataChanged = GenericFrame.removeHiddenWidgets(widgets);
      
      if (dataChanged == null || dataChanged.length == 0)
      {
         return;
      }

      editingBlock(frame, dataChanged, null, enclosing, label, block, CommonFrame.UPDATE);
   }
   
   /**
    * Execute the given editing block for the given frame and widget list
    * with <code>UPDATE</code> semanics. All looping, sub-transaction
    * properties and block properties will be honored.  The exit from the
    * editing block will be based on the given <code>GO-ON</code> event list.
    *
    * @param    frame
    *           The frame for which the editing block is associated.
    * @param    widgets
    *           The widgets in the given frame that are to be enabled for
    *           editing.
    * @param    goOn
    *           The exit conditions for this loop.
    * @param    label
    *           The label of the block for use in control flow statements
    *           such as <code>LEAVE</code> or <code>NEXT</code>.
    * @param    block
    *           The code for the editing block body.
    */
   public static void updateEditingUnlessHidden(CommonFrame    frame,
                                                FrameElement[] widgets,
                                                EventList      goOn,
                                                String         label,
                                                Block          block)
   {
      FrameElement[] dataChanged = GenericFrame.removeHiddenWidgets(widgets);
      
      if (dataChanged == null || dataChanged.length == 0)
      {
         return;
      }

      editingBlock(frame, dataChanged, goOn, null, label, block, CommonFrame.UPDATE);
   }
   
   /**
    * Execute the given editing block for the given frame and widget list
    * with <code>UPDATE</code> semanics. All looping, sub-transaction
    * properties and block properties will be honored.  The exit from the
    * editing block will be based on the given <code>GO-ON</code> event list.
    *
    * @param    frame
    *           The frame for which the editing block is associated.
    * @param    widgets
    *           The widgets in the given frame that are to be enabled for
    *           editing.
    * @param    goOn
    *           The exit conditions for this loop.
    * @param    enclosing
    *           The list of enclosing blocks of which this class is unaware.
    *           Any LEAVE or NEXT that references one of those enclosing
    *           blocks must not unwind the stack further using an exception,
    *           but rather it must return and let the caller check to see if
    *           a deferred LEAVE or NEXT must be honored.
    * @param    label
    *           The label of the block for use in control flow statements
    *           such as <code>LEAVE</code> or <code>NEXT</code>.
    * @param    block
    *           The code for the editing block body.
    */
   public static void updateEditingUnlessHidden(CommonFrame    frame,
                                                FrameElement[] widgets,
                                                EventList      goOn,
                                                String[]       enclosing,
                                                String         label,
                                                Block          block)
   {
      FrameElement[] dataChanged = GenericFrame.removeHiddenWidgets(widgets);
      
      if (dataChanged == null || dataChanged.length == 0)
      {
         return;
      }

      editingBlock(frame, dataChanged, goOn, enclosing, label, block, CommonFrame.UPDATE);
   }

   /**
    * Execute the given editing block for the given frame and widget list
    * with <code>PROMPT-FOR</code> semanics. All looping, sub-transaction
    * properties and block properties will be honored.
    *
    * @param    frame
    *           The frame for which the editing block is associated.
    * @param    widgets
    *           The widgets in the given frame that are to be enabled for
    *           editing.
    * @param    label
    *           The label of the block for use in control flow statements
    *           such as <code>LEAVE</code> or <code>NEXT</code>.
    * @param    block
    *           The code for the editing block body.
    */
   public static void promptForEditing(CommonFrame    frame,
                                       FrameElement[] widgets,
                                       String         label,
                                       Block          block)
   {
      editingBlock(frame, widgets, null,  null, label, block, CommonFrame.PROMPT_FOR);
   }
   
   /**
    * Execute the given editing block for the given frame and widget list
    * with <code>PROMPT-FOR</code> semanics. All looping, sub-transaction
    * properties and block properties will be honored.
    *
    * @param    frame
    *           The frame for which the editing block is associated.
    * @param    widgets
    *           The widgets in the given frame that are to be enabled for
    *           editing.
    * @param    enclosing
    *           The list of enclosing blocks of which this class is unaware.
    *           Any LEAVE or NEXT that references one of those enclosing
    *           blocks must not unwind the stack further using an exception,
    *           but rather it must return and let the caller check to see if
    *           a deferred LEAVE or NEXT must be honored.
    * @param    label
    *           The label of the block for use in control flow statements
    *           such as <code>LEAVE</code> or <code>NEXT</code>.
    * @param    block
    *           The code for the editing block body.
    */
   public static void promptForEditing(CommonFrame    frame,
                                       FrameElement[] widgets,
                                       String[]       enclosing,
                                       String         label,
                                       Block          block)
   {
      editingBlock(frame, widgets, null, enclosing, label, block, CommonFrame.PROMPT_FOR);
   }
   
   /**
    * Execute the given editing block for the given frame and widget list
    * with <code>PROMPT-FOR</code> semanics. All looping, sub-transaction
    * properties and block properties will be honored.  The exit from the
    * editing block will be based on the given <code>GO-ON</code> event list.
    *
    * @param    frame
    *           The frame for which the editing block is associated.
    * @param    widgets
    *           The widgets in the given frame that are to be enabled for
    *           editing.
    * @param    goOn
    *           The exit conditions for this loop.
    * @param    label
    *           The label of the block for use in control flow statements
    *           such as <code>LEAVE</code> or <code>NEXT</code>.
    * @param    block
    *           The code for the editing block body.
    */
   public static void promptForEditing(CommonFrame    frame,
                                       FrameElement[] widgets,
                                       EventList      goOn,
                                       String         label,
                                       Block          block)
   {
      editingBlock(frame, widgets, goOn, null, label, block, CommonFrame.PROMPT_FOR);
   }
   
   /**
    * Execute the given editing block for the given frame and widget list
    * with <code>PROMPT-FOR</code> semanics. All looping, sub-transaction
    * properties and block properties will be honored.  The exit from the
    * editing block will be based on the given <code>GO-ON</code> event list.
    *
    * @param    frame
    *           The frame for which the editing block is associated.
    * @param    widgets
    *           The widgets in the given frame that are to be enabled for
    *           editing.
    * @param    goOn
    *           The exit conditions for this loop.
    * @param    enclosing
    *           The list of enclosing blocks of which this class is unaware.
    *           Any LEAVE or NEXT that references one of those enclosing
    *           blocks must not unwind the stack further using an exception,
    *           but rather it must return and let the caller check to see if
    *           a deferred LEAVE or NEXT must be honored.
    * @param    label
    *           The label of the block for use in control flow statements
    *           such as <code>LEAVE</code> or <code>NEXT</code>.
    * @param    block
    *           The code for the editing block body.
    */
   public static void promptForEditing(CommonFrame    frame,
                                       FrameElement[] widgets,
                                       EventList      goOn,
                                       String[]       enclosing,
                                       String         label,
                                       Block          block)
   {
      editingBlock(frame, widgets, goOn, enclosing, label, block, CommonFrame.PROMPT_FOR);
   }
   
   /**
    * Execute the given editing block for the given frame and widget list
    * with <code>SET</code> semanics. All looping, sub-transaction
    * properties and block properties will be honored.
    *
    * @param    frame
    *           The frame for which the editing block is associated.
    * @param    widgets
    *           The widgets in the given frame that are to be enabled for
    *           editing.
    * @param    label
    *           The label of the block for use in control flow statements
    *           such as <code>LEAVE</code> or <code>NEXT</code>.
    * @param    block
    *           The code for the editing block body.
    */
   public static void setEditing(CommonFrame    frame,
                                 FrameElement[] widgets,
                                 String         label,
                                 Block          block)
   {
      editingBlock(frame, widgets, null, null, label, block, CommonFrame.SET);
   }
   
   /**
    * Execute the given editing block for the given frame and widget list
    * with <code>SET</code> semanics. All looping, sub-transaction
    * properties and block properties will be honored.
    *
    * @param    frame
    *           The frame for which the editing block is associated.
    * @param    widgets
    *           The widgets in the given frame that are to be enabled for
    *           editing.
    * @param    enclosing
    *           The list of enclosing blocks of which this class is unaware.
    *           Any LEAVE or NEXT that references one of those enclosing
    *           blocks must not unwind the stack further using an exception,
    *           but rather it must return and let the caller check to see if
    *           a deferred LEAVE or NEXT must be honored.
    * @param    label
    *           The label of the block for use in control flow statements
    *           such as <code>LEAVE</code> or <code>NEXT</code>.
    * @param    block
    *           The code for the editing block body.
    */
   public static void setEditing(CommonFrame    frame,
                                 FrameElement[] widgets,
                                 String[]       enclosing,
                                 String         label,
                                 Block          block)
   {
      editingBlock(frame, widgets, null, enclosing, label, block, CommonFrame.SET);
   }
   
   /**
    * Execute the given editing block for the given frame and widget list
    * with <code>SET</code> semanics. All looping, sub-transaction
    * properties and block properties will be honored.  The exit from the
    * editing block will be based on the given <code>GO-ON</code> event list.
    *
    * @param    frame
    *           The frame for which the editing block is associated.
    * @param    widgets
    *           The widgets in the given frame that are to be enabled for
    *           editing.
    * @param    goOn
    *           The exit conditions for this loop.
    * @param    label
    *           The label of the block for use in control flow statements
    *           such as <code>LEAVE</code> or <code>NEXT</code>.
    * @param    block
    *           The code for the editing block body.
    */
   public static void setEditing(CommonFrame    frame,
                                 FrameElement[] widgets,
                                 EventList      goOn,
                                 String         label,
                                 Block          block)
   {
      editingBlock(frame, widgets, goOn, null, label, block, CommonFrame.SET);
   }
   
   /**
    * Execute the given editing block for the given frame and widget list
    * with <code>SET</code> semanics. All looping, sub-transaction
    * properties and block properties will be honored.  The exit from the
    * editing block will be based on the given <code>GO-ON</code> event list.
    *
    * @param    frame
    *           The frame for which the editing block is associated.
    * @param    widgets
    *           The widgets in the given frame that are to be enabled for
    *           editing.
    * @param    goOn
    *           The exit conditions for this loop.
    * @param    enclosing
    *           The list of enclosing blocks of which this class is unaware.
    *           Any LEAVE or NEXT that references one of those enclosing
    *           blocks must not unwind the stack further using an exception,
    *           but rather it must return and let the caller check to see if
    *           a deferred LEAVE or NEXT must be honored.
    * @param    label
    *           The label of the block for use in control flow statements
    *           such as <code>LEAVE</code> or <code>NEXT</code>.
    * @param    block
    *           The code for the editing block body.
    */
   public static void setEditing(CommonFrame    frame,
                                 FrameElement[] widgets,
                                 EventList      goOn,
                                 String[]       enclosing,
                                 String         label,
                                 Block          block)
   {
      editingBlock(frame, widgets, goOn, enclosing, label, block, CommonFrame.SET);
   }
   
   /**
    * Execute the given editing block for the given frame and widget list
    * with <code>UPDATE</code> semanics. All looping, sub-transaction
    * properties and block properties will be honored.
    *
    * @param    frame
    *           The frame for which the editing block is associated.
    * @param    widgets
    *           The widgets in the given frame that are to be enabled for
    *           editing.
    * @param    label
    *           The label of the block for use in control flow statements
    *           such as <code>LEAVE</code> or <code>NEXT</code>.
    * @param    block
    *           The code for the editing block body.
    */
   public static void updateEditing(CommonFrame    frame,
                                    FrameElement[] widgets,
                                    String         label,
                                    Block          block)
   {
      editingBlock(frame, widgets, null, null, label, block, CommonFrame.UPDATE);
   }
   
   /**
    * Execute the given editing block for the given frame and widget list
    * with <code>UPDATE</code> semanics. All looping, sub-transaction
    * properties and block properties will be honored.
    *
    * @param    frame
    *           The frame for which the editing block is associated.
    * @param    widgets
    *           The widgets in the given frame that are to be enabled for
    *           editing.
    * @param    enclosing
    *           The list of enclosing blocks of which this class is unaware.
    *           Any LEAVE or NEXT that references one of those enclosing
    *           blocks must not unwind the stack further using an exception,
    *           but rather it must return and let the caller check to see if
    *           a deferred LEAVE or NEXT must be honored.
    * @param    label
    *           The label of the block for use in control flow statements
    *           such as <code>LEAVE</code> or <code>NEXT</code>.
    * @param    block
    *           The code for the editing block body.
    */
   public static void updateEditing(CommonFrame    frame,
                                    FrameElement[] widgets,
                                    String[]       enclosing,
                                    String         label,
                                    Block          block)
   {
      editingBlock(frame, widgets, null, enclosing, label, block, CommonFrame.UPDATE);
   }
   
   /**
    * Execute the given editing block for the given frame and widget list
    * with <code>UPDATE</code> semanics. All looping, sub-transaction
    * properties and block properties will be honored.  The exit from the
    * editing block will be based on the given <code>GO-ON</code> event list.
    *
    * @param    frame
    *           The frame for which the editing block is associated.
    * @param    widgets
    *           The widgets in the given frame that are to be enabled for
    *           editing.
    * @param    goOn
    *           The exit conditions for this loop.
    * @param    label
    *           The label of the block for use in control flow statements
    *           such as <code>LEAVE</code> or <code>NEXT</code>.
    * @param    block
    *           The code for the editing block body.
    */
   public static void updateEditing(CommonFrame    frame,
                                    FrameElement[] widgets,
                                    EventList      goOn,
                                    String         label,
                                    Block          block)
   {
      editingBlock(frame, widgets, goOn, null, label, block, CommonFrame.UPDATE);
   }
   
   /**
    * Execute the given editing block for the given frame and widget list
    * with <code>UPDATE</code> semanics. All looping, sub-transaction
    * properties and block properties will be honored.  The exit from the
    * editing block will be based on the given <code>GO-ON</code> event list.
    *
    * @param    frame
    *           The frame for which the editing block is associated.
    * @param    widgets
    *           The widgets in the given frame that are to be enabled for
    *           editing.
    * @param    goOn
    *           The exit conditions for this loop.
    * @param    enclosing
    *           The list of enclosing blocks of which this class is unaware.
    *           Any LEAVE or NEXT that references one of those enclosing
    *           blocks must not unwind the stack further using an exception,
    *           but rather it must return and let the caller check to see if
    *           a deferred LEAVE or NEXT must be honored.
    * @param    label
    *           The label of the block for use in control flow statements
    *           such as <code>LEAVE</code> or <code>NEXT</code>.
    * @param    block
    *           The code for the editing block body.
    */
   public static void updateEditing(CommonFrame    frame,
                                    FrameElement[] widgets,
                                    EventList      goOn,
                                    String[]       enclosing,
                                    String         label,
                                    Block          block)
   {
      editingBlock(frame, widgets, goOn, enclosing, label, block, CommonFrame.UPDATE);
   }
   
   /**
    * Break out of the nearest enclosing block.
    * 
    * @throws   LeaveUnwindException 
    */
   public static void leave()
   throws LeaveUnwindException
   {
      leave("");
   }
   
   /**
    * Break out of the block associated with the given label.  This will
    * unwind the stack until the proper block has been reached.  At that
    * point the block will be left using the Java "break" statement.
    *
    * @param    label
    *           The name of the block to be left.
    *           
    * @throws   LeaveUnwindException 
    */
   public static void leave(String label)
   throws LeaveUnwindException
   {
      leave(work.obtain(), label);
   }
   
   /**
    * Detect if there is a pending leave for the block named by the given
    * label. If so, this deferred leave flag will be cleared and 
    * <code>true</code> will be returned.  The caller is responsible for
    * ensuring that the leave request is fully granted as no further state
    * will be available for subsequent processing.
    *
    * @param    label
    *           The name of the block to be checked against the deferred
    *           leave block name.
    *
    * @return   <code>true</code> if there is a pending deferred leave and
    *           the name of the block to be left is the same as the given
    *           label. If the pending deferred block name is the "" (empty
    *           string), that is the equivalent of matching "any block" and
    *           so the first call to this method after that is set will cause
    *           a <code>true</code> to be returned.
    */
   public static boolean deferredLeave(String label)
   {
      return deferredLeaveWorker(null, label);
   }
   
   /**
    * Continue (iterate) the nearest enclosing block.
    * 
    * @throws   NextUnwindException 
    */
   public static void next()
   throws NextUnwindException
   {
      next("");
   }
   
   /**
    * Continue (iterate) the block associated with the given label.  This will
    * unwind the stack until the proper block has been reached.  At that
    * point the block will be iterated using the Java "continue" statement.
    *
    * @param    label
    *           The name of the block to be iterated.
    *
    * @throws   NextUnwindException 
    */
   public static void next(String label)
   throws NextUnwindException
   {
      next(work.obtain(), label);
   }
   
   /**
    * Detect if there is a pending next for the block named by the given
    * label. If so, this deferred next flag will be cleared and 
    * <code>true</code> will be returned.  The caller is responsible for
    * ensuring that the next request is fully granted as no further state
    * will be available for subsequent processing.
    *
    * @param    label
    *           The name of the block to be checked against the deferred
    *           next block name.
    *
    * @return   <code>true</code> if there is a pending deferred next and
    *           the name of the block to be iterated is the same as the given
    *           label. If the pending deferred block name is the "" (empty
    *           string), that is the equivalent of matching "any block" and
    *           so the first call to this method after that is set will cause
    *           a <code>true</code> to be returned.
    */
   public static boolean deferredNext(String label)
   {
      return deferredNextWorker(null, label);
   }
   
   /**
    * Raise the STOP condition and cause control to be transferred to the
    * nearest enclosing block that handles the associated condition.
    * 
    * @throws   StopConditionException 
    */
   public static void stop()
   throws StopConditionException
   {
      String msg = "Explicit STOP.";
      ErrorManager.handleStopException(msg);
   }
   
   /**
    * Raise the QUIT condition and cause control to be transferred to the
    * nearest enclosing block that handles the associated condition.
    * 
    * @throws  QuitConditionException 
    */
   public static void quit()
   throws QuitConditionException
   {
      throw new QuitConditionException("Explicit QUIT.");
   }
   
   /**
    * Return from the nearest enclosing top-level block. Sets the default
    * <code>RETURN-VALUE</code> to "" (empty string) for internal/external
    * procedures and triggers. Leaves <code>unknown value</code> as the
    * default return from a user-defined function.
    * 
    * @throws   ReturnUnwindException 
    */
   public static void returnNormal()
   throws ReturnUnwindException
   {
      returnWorker(null, null, ReturnType.NORMAL);
   }
   
   /**
    * Return from the nearest enclosing top-level block. Sets the
    * <code>RETURN-VALUE</code> to the given <code>character</code> value for
    * internal/external procedures and triggers. Saves the given value as the
    * return value for a user-defined function.  If <code>val</code> is
    * <code>null</code>, then <code>RETURN-VALUE</code> will be set to the
    * "" (empty string) for internal/external procedures and triggers. If
    * <code>val</code> is <code>null</code> for a user-defined function,
    * <code>unknown value</code> will be the default return.
    *
    * @param    val
    *           The value to return or <code>null</code>.  For procedures
    *           or triggers, this must be a <code>character</code> value.
    *           
    * @throws   ReturnUnwindException 
    */
   public static void returnNormal(WrappedResource val)
   throws ReturnUnwindException
   {
      returnNormal(new handle(val));
   }

   /**
    * Return from the nearest enclosing top-level block. Sets the
    * <code>RETURN-VALUE</code> to the given <code>character</code> value for
    * internal/external procedures and triggers. Saves the given value as the
    * return value for a user-defined function.  If <code>val</code> is
    * <code>null</code>, then <code>RETURN-VALUE</code> will be set to the
    * "" (empty string) for internal/external procedures and triggers. If
    * <code>val</code> is <code>null</code> for a user-defined function,
    * <code>unknown value</code> will be the default return.
    *
    * @param    val
    *           The value to return or <code>null</code>.  For procedures
    *           or triggers, this must be a <code>character</code> value.
    *
    * @throws   ReturnUnwindException
    */
   public static void returnNormal(Stream val)
   throws ReturnUnwindException
   {
      returnNormal(new handle(val));
   }
   
   /**
    * Return from the nearest enclosing top-level block. Sets the
    * <code>RETURN-VALUE</code> to the given <code>character</code> value for
    * internal/external procedures and triggers. Saves the given value as the
    * return value for a user-defined function.  If <code>val</code> is
    * <code>null</code>, then <code>RETURN-VALUE</code> will be set to the
    * "" (empty string) for internal/external procedures and triggers. If
    * <code>val</code> is <code>null</code> for a user-defined function,
    * <code>unknown value</code> will be the default return.
    *
    * @param    val
    *           The value to return or <code>null</code>.  For procedures
    *           or triggers, this must be a <code>character</code> value.
    *           
    * @throws   ReturnUnwindException 
    */
   public static void returnNormal(BaseDataType val)
   throws ReturnUnwindException
   {
      returnWorker(null, val, ReturnType.NORMAL);
   }
   
   /**
    * Return from the nearest enclosing top-level block. Sets the
    * <code>RETURN-VALUE</code> to the given <code>character</code> value for
    * internal/external procedures and triggers. Saves the given value as the
    * return value for a user-defined function.  If <code>val</code> is
    * <code>null</code>, then <code>RETURN-VALUE</code> will be set to the
    * "" (empty string) for internal/external procedures and triggers. If
    * <code>val</code> is <code>null</code> for a user-defined function,
    * <code>unknown value</code> will be the default return.
    *
    * @param    val
    *           The value to return or <code>null</code>.  For procedures
    *           or triggers, this must be a <code>character</code> value.
    *           
    * @throws   ReturnUnwindException 
    */
   public static void returnExtentNormal(BaseDataType[] val)
   throws ReturnUnwindException
   {
      returnWorker(null, val, ReturnType.NORMAL);
   }
   
   /**
    * Return from the nearest enclosing top-level block. Sets the
    * <code>RETURN-VALUE</code> to the given <code>character</code> value for
    * internal/external procedures and triggers. Saves the given value as the
    * return value for a user-defined function.  If <code>val</code> is
    * <code>null</code>, then <code>RETURN-VALUE</code> will be set to the
    * "" (empty string) for internal/external procedures and triggers. If
    * <code>val</code> is <code>null</code> for a user-defined function,
    * <code>unknown value</code> will be the default return.
    *
    * @param    val
    *           The value to return or <code>null</code>.  For procedures
    *           or triggers, this must be a <code>character</code> value.
    *           
    * @throws   ReturnUnwindException 
    */
   public static void returnNormal(String val)
   throws ReturnUnwindException
   {
      returnWorker(new character(val), ReturnType.NORMAL);
   }
   
   /**
    * Return from the nearest enclosing top-level block. This should not be
    * used for internal/external procedures and triggers, since the
    * <code>RETURN-VALUE</code> can only be set to a character expression.
    * <p>
    * For a user-defined function, this saves the given value as the function
    * return value.
    *
    * @param    val
    *           The value to return.
    *           
    * @throws   ReturnUnwindException 
    */
   public static void returnNormal(int val)
   throws ReturnUnwindException
   {
      returnWorker(new integer(val), ReturnType.NORMAL);
   }
   
   /**
    * Return from the nearest enclosing top-level block. This should not be
    * used for internal/external procedures and triggers, since the
    * <code>RETURN-VALUE</code> can only be set to a character expression.
    * <p>
    * For a user-defined function, this saves the given value as the function
    * return value.
    *
    * @param    val
    *           The value to return.
    *           
    * @throws   ReturnUnwindException 
    */
   public static void returnNormal(long val)
   throws ReturnUnwindException
   {
      returnWorker(new int64(val), ReturnType.NORMAL);
   }

   /**
    * Return from the nearest enclosing top-level block. This should not be
    * used for internal/external procedures and triggers, since the
    * <code>RETURN-VALUE</code> can only be set to a character expression.
    * <p>
    * For a user-defined function, this saves the given value as the function
    * return value.
    *
    * @param    val
    *           The value to return.
    *           
    * @throws   ReturnUnwindException 
    */
   public static void returnNormal(double val)
   throws ReturnUnwindException
   {
      returnWorker(new decimal(val), ReturnType.NORMAL);
   }
   
   /**
    * Return from the nearest enclosing top-level block. This should not be
    * used for internal/external procedures and triggers, since the
    * <code>RETURN-VALUE</code> can only be set to a character expression.
    * <p>
    * For a user-defined function, this saves the given value as the function
    * return value.
    *
    * @param    val
    *           The value to return.
    *           
    * @throws   ReturnUnwindException 
    */
   public static void returnNormal(boolean val)
   throws ReturnUnwindException
   {
      returnWorker(logical.of(val), ReturnType.NORMAL);
   }

   /**
    * Return from the nearest enclosing top-level block. Sets the default
    * <code>RETURN-VALUE</code> to "" (empty string) for internal/external
    * procedures and triggers. Leaves <code>unknown value</code> as the
    * default return from a user-defined function.
    * 
    * @throws   ReturnUnwindException 
    */
   public static void storeReturnValue()
   throws ReturnUnwindException
   {
      returnWorker(null, null, ReturnType.STORE);
   }
   
   /**
    * Return from the nearest enclosing top-level block. Sets the
    * <code>RETURN-VALUE</code> to the given <code>character</code> value for
    * internal/external procedures and triggers. Saves the given value as the
    * return value for a user-defined function.  If <code>val</code> is
    * <code>null</code>, then <code>RETURN-VALUE</code> will be set to the
    * "" (empty string) for internal/external procedures and triggers. If
    * <code>val</code> is <code>null</code> for a user-defined function,
    * <code>unknown value</code> will be the default return.
    *
    * @param    val
    *           The value to return or <code>null</code>.  For procedures
    *           or triggers, this must be a <code>character</code> value.
    *           
    * @throws   ReturnUnwindException 
    */
   public static void storeReturnValue(WrappedResource val)
   throws ReturnUnwindException
   {
      returnWorker(null, new handle(val), ReturnType.STORE);
   }

   /**
    * Return from the nearest enclosing top-level block. Sets the
    * <code>RETURN-VALUE</code> to the given <code>character</code> value for
    * internal/external procedures and triggers. Saves the given value as the
    * return value for a user-defined function.  If <code>val</code> is
    * <code>null</code>, then <code>RETURN-VALUE</code> will be set to the
    * "" (empty string) for internal/external procedures and triggers. If
    * <code>val</code> is <code>null</code> for a user-defined function,
    * <code>unknown value</code> will be the default return.
    *
    * @param    val
    *           The value to return or <code>null</code>.  For procedures
    *           or triggers, this must be a <code>character</code> value.
    *
    * @throws   ReturnUnwindException
    */
   public static void storeReturnValue(Stream val)
   throws ReturnUnwindException
   {
      returnWorker(null, new handle(val), ReturnType.STORE);
   }
   
   /**
    * Return from the nearest enclosing top-level block. Sets the
    * <code>RETURN-VALUE</code> to the given <code>character</code> value for
    * internal/external procedures and triggers. Saves the given value as the
    * return value for a user-defined function.  If <code>val</code> is
    * <code>null</code>, then <code>RETURN-VALUE</code> will be set to the
    * "" (empty string) for internal/external procedures and triggers. If
    * <code>val</code> is <code>null</code> for a user-defined function,
    * <code>unknown value</code> will be the default return.
    *
    * @param    val
    *           The value to return or <code>null</code>.  For procedures
    *           or triggers, this must be a <code>character</code> value.
    *           
    * @throws   ReturnUnwindException 
    */
   public static void storeReturnValue(BaseDataType val)
   throws ReturnUnwindException
   {
      returnWorker(null, val, ReturnType.STORE);
   }
   
   /**
    * Return from the nearest enclosing top-level block. Sets the
    * <code>RETURN-VALUE</code> to the given <code>character</code> value for
    * internal/external procedures and triggers. Saves the given value as the
    * return value for a user-defined function.  If <code>val</code> is
    * <code>null</code>, then <code>RETURN-VALUE</code> will be set to the
    * "" (empty string) for internal/external procedures and triggers. If
    * <code>val</code> is <code>null</code> for a user-defined function,
    * <code>unknown value</code> will be the default return.
    *
    * @param    val
    *           The value to return or <code>null</code>.  For procedures
    *           or triggers, this must be a <code>character</code> value.
    *           
    * @throws   ReturnUnwindException 
    */
   public static void storeExtentReturnValue(BaseDataType[] val)
   throws ReturnUnwindException
   {
      returnWorker(null, val, ReturnType.STORE);
   }
   
   /**
    * Return from the nearest enclosing top-level block. Sets the
    * <code>RETURN-VALUE</code> to the given <code>character</code> value for
    * internal/external procedures and triggers. Saves the given value as the
    * return value for a user-defined function.  If <code>val</code> is
    * <code>null</code>, then <code>RETURN-VALUE</code> will be set to the
    * "" (empty string) for internal/external procedures and triggers. If
    * <code>val</code> is <code>null</code> for a user-defined function,
    * <code>unknown value</code> will be the default return.
    *
    * @param    val
    *           The value to return or <code>null</code>.  For procedures
    *           or triggers, this must be a <code>character</code> value.
    *           
    * @throws   ReturnUnwindException 
    */
   public static void storeReturnValue(String val)
   throws ReturnUnwindException
   {
      returnWorker(null, new character(val), ReturnType.STORE);
   }
   
   /**
    * Return from the nearest enclosing top-level block. This should not be
    * used for internal/external procedures and triggers, since the
    * <code>RETURN-VALUE</code> can only be set to a character expression.
    * <p>
    * For a user-defined function, this saves the given value as the function
    * return value.
    *
    * @param    val
    *           The value to return.
    *           
    * @throws   ReturnUnwindException 
    */
   public static void storeReturnValue(int val)
   throws ReturnUnwindException
   {
      returnWorker(null, new integer(val), ReturnType.STORE);
   }
   
   /**
    * Return from the nearest enclosing top-level block. This should not be
    * used for internal/external procedures and triggers, since the
    * <code>RETURN-VALUE</code> can only be set to a character expression.
    * <p>
    * For a user-defined function, this saves the given value as the function
    * return value.
    *
    * @param    val
    *           The value to return.
    *           
    * @throws   ReturnUnwindException 
    */
   public static void storeReturnValue(long val)
   throws ReturnUnwindException
   {
      returnWorker(null, new int64(val), ReturnType.STORE);
   }

   /**
    * Return from the nearest enclosing top-level block. This should not be
    * used for internal/external procedures and triggers, since the
    * <code>RETURN-VALUE</code> can only be set to a character expression.
    * <p>
    * For a user-defined function, this saves the given value as the function
    * return value.
    *
    * @param    val
    *           The value to return.
    *           
    * @throws   ReturnUnwindException 
    */
   public static void storeReturnValue(double val)
   throws ReturnUnwindException
   {
      returnWorker(null, new decimal(val), ReturnType.STORE);
   }
   
   /**
    * Return from the nearest enclosing top-level block. This should not be
    * used for internal/external procedures and triggers, since the
    * <code>RETURN-VALUE</code> can only be set to a character expression.
    * <p>
    * For a user-defined function, this saves the given value as the function
    * return value.
    *
    * @param    val
    *           The value to return.
    *           
    * @throws   ReturnUnwindException 
    */
   public static void storeReturnValue(boolean val)
   throws ReturnUnwindException
   {
      returnWorker(null, logical.of(val), ReturnType.STORE);
   }   
   
   /**
    * Return from the nearest enclosing top-level block. Sets the default
    * <code>RETURN-VALUE</code> to "" (empty string) for internal/external
    * procedures and triggers. Leaves <code>unknown value</code> as the
    * default return from a user-defined function.
    * <p>
    * If executed for a trigger, force the event which caused the trigger
    * execution to be consumed (no default processing of that event should
    * occur).
    *           
    * @throws   ReturnUnwindException 
    */
   public static void returnConsume()
   throws ReturnUnwindException
   {
      returnWorker(null, null, ReturnType.CONSUME);
   }
   
   /**
    * Return from the nearest enclosing top-level block, consuming any pending
    * event processing. Sets the <code>RETURN-VALUE</code> to the given value
    * for internal/external procedures and triggers.  Should not be called
    * for a user-defined function.
    * <p>
    * If executed for a trigger, force the event which caused the trigger
    * execution to be consumed (no default processing of that event should
    * occur).
    *
    * @param    val
    *           The value to return or <code>null</code>.
    *           
    * @throws   ReturnUnwindException 
    */
   public static void returnConsume(character val)
   throws ReturnUnwindException
   {
      returnWorker(val, ReturnType.CONSUME);
   }
   
   /**
    * Return from the nearest enclosing top-level block, consuming any pending
    * event processing. Sets the <code>RETURN-VALUE</code> to the given value
    * for internal/external procedures and triggers. Sets the given value as
    * the return value for a user-defined function.
    * <p>
    * If executed for a trigger, force the event which caused the trigger
    * execution to be consumed (no default processing of that event should
    * occur).
    *
    * @param    val
    *           The value to return or <code>null</code>.
    *           
    * @throws   ReturnUnwindException 
    */
   public static void returnConsume(String val)
   throws ReturnUnwindException
   {
      returnWorker(new character(val), ReturnType.CONSUME);
   }
   
   /**
    * Return from the nearest enclosing top-level block. Sets the default
    * <code>RETURN-VALUE</code> to "" (empty string) for internal/external
    * procedures and triggers. Leaves <code>unknown value</code> as the
    * default return from a user-defined function.
    * <p>
    * If silent error mode is not enabled in the caller, an <code>ERROR</code>
    * condition will be raised here and will unwind the stack (it will not
    * be processed, but will instead it will be rethrown) until it reaches
    * the caller's context at which time the error will be honored. If silent
    * error mode is enabled, the error data will be stored in the 
    * <code>ERROR-STATUS</code> facility and a return will be executed to
    * return processing to the caller without raising the error condition
    * (without throwing an exception).
    *           
    * @throws   ReturnUnwindException 
    * @throws   ErrorConditionException 
    */
   public static void returnError()
   throws ReturnUnwindException,
          ErrorConditionException
   {
      returnWorker(null, null, ReturnType.ERROR);
   }
   
   /**
    * Return from the nearest enclosing top-level block. If the given value
    * is <code>null</code>, this sets the default <code>RETURN-VALUE</code>
    * to "" (empty string) for internal/external procedures and triggers.
    * It leaves <code>unknown value</code> as the default return from a
    * user-defined function.  If the value is not <code>null</code>, then
    * that value (if it is a <code>character</code> type) will be set as the
    * <code>RETURN-VALUE</code> for internal/external procedures and triggers.
    * If not <code>null</code>, the value will be returned as the function
    * return value for user-defined functions.
    * <p>
    * If silent error mode is not enabled in the caller, an <code>ERROR</code>
    * condition will be raised here and will unwind the stack (it will not
    * be processed, but will instead it will be rethrown) until it reaches
    * the caller's context at which time the error will be honored. If silent
    * error mode is enabled, the error data will be stored in the 
    * <code>ERROR-STATUS</code> facility and a return will be executed to
    * return processing to the caller without raising the error condition
    * (without throwing an exception).
    *
    * @param    val
    *           The value to return.
    *           
    * @throws   ReturnUnwindException 
    * @throws   ErrorConditionException 
    */
   public static void returnError(character val)
   throws ReturnUnwindException,
          ErrorConditionException
   {
      returnWorker(val, ReturnType.ERROR);
   }
   
   /**
    * Return from the nearest enclosing top-level block. If the given value
    * is <code>null</code>, this sets the default <code>RETURN-VALUE</code>
    * to "" (empty string) for internal/external procedures and triggers.
    * It leaves <code>unknown value</code> as the default return from a
    * user-defined function.  If the value is not <code>null</code>, then
    * that value will be set as the <code>RETURN-VALUE</code> for internal/
    * external procedures and triggers. If not <code>null</code>, the value
    * will be returned as the function return value for user-defined
    * functions.
    * <p>
    * If silent error mode is not enabled in the caller, an <code>ERROR</code>
    * condition will be raised here and will unwind the stack (it will not
    * be processed, but will instead it will be rethrown) until it reaches
    * the caller's context at which time the error will be honored. If silent
    * error mode is enabled, the error data will be stored in the 
    * <code>ERROR-STATUS</code> facility and a return will be executed to
    * return processing to the caller without raising the error condition
    * (without throwing an exception).
    *
    * @param    val
    *           The value to return.
    *           
    * @throws   ReturnUnwindException 
    * @throws   ErrorConditionException 
    */
   public static void returnError(String val)
   throws ReturnUnwindException,
          ErrorConditionException
   {
      returnWorker(new character(val), ReturnType.ERROR);
   }
   
   /**
    * Return from the nearest enclosing top-level block by throwing the specified legacy error.
    * 
    * @param    error
    *           The error object.
    * 
    * @throws   LegacyErrorException
    */
   public static void returnError(object<? extends LegacyError> error)
   throws ReturnUnwindException,
          ErrorConditionException
   {
      if (!error._isValid() || !LegacyError.class.isAssignableFrom(error.ref.getClass()))
      {
         ErrorManager.recordOrThrowError(14477,
                                         "RETURN ERROR statement failed with an invalid error object", 
                                         false, false);
         return;
      }
      
      WorkArea wa = work.get();
      markReturnError(wa);
      
      setReturnValue(wa, error.ref);

      LegacyErrorException lex = new LegacyErrorException(error, true);
      lex.setExplicit(true);
      
      if (mustThrowLegacyError(wa, error.ref.getClass()))
      {
         throw lex;
      }
      else
      {
         wa.tm.triggerErrorInCaller(lex);
      }
   }
   
   /**
    * Execute the default block associated with a <code>CATCH</code> statement.
    *
    * @param    label
    *           The block name of the current block.
    * @param    block
    *           The code to execute.
    */
   public static void catchBlock(String label, Block block)
   {
      catchBlock(TransactionType.NONE, label, block);
   }
   
   /**
    * Execute the default block associated with a <code>CATCH</code> statement.
    *
    * @param    lvl
    *           The transaction level to be honored.
    * @param    label
    *           The block name of the current block.
    * @param    block
    *           The code to execute.
    */
   public static void catchBlock(TransactionType lvl, String label, Block block)
   {
      String[] enclosing = null;
      block.pre();
      
      BlockType blockType = BlockType.CATCH;
      
      int ttype = convertTransType(lvl, blockType);
      
      OnPhrase[] defOn = new OnPhrase[1];
      defOn[0] = new OnPhrase(Condition.ERROR, Action.THROW, label);
      
      WorkArea wa = work.obtain();
      int props = decodeConditions(null, defOn);
      
      wa.tm.pushScope(label, ttype, props, false, false, false, false, blockType);
      
      try
      {
         // give the block a chance to initialize its state and don't
         // repeat that during retry
         block.init();
         wa.tm.blockSetup();
         
         blockLabel:
         try
         {
            processBody(wa, block, null, defOn);
         }
            
         catch (LegacyErrorException lex)
         {
            processLegacyException(wa, lex);
         }
         
         catch (ConditionException ce)
         {
            wa.tm.notifyCondition(ce);
            
            switch (processCondition(wa, null, defOn, ce, enclosing, "catchBlock"))
            {
               // note that this is not an iterating block so a leave or
               // next targeted at this block must always act the same
               case BREAK:
               case CONTINUE:
                  break blockLabel;
               default:
                  break;
            }
         }
         
         catch (RetryUnwindException rue)
         {
            wa.tm.honorRetry(rue);
         }
         
         catch (LeaveUnwindException lue)
         {
            if (testLeave(wa, enclosing, "catchBlock") == Disposition.BREAK)
            {
               // the LEAVE targeted this block or an enclosing
               // non-managed block
               break blockLabel;
            }
            
            // the LEAVE must be referencing an enclosing block which IS
            // known to the block manager OR to one of the other enclosing
            // managed blocks, so keep unwinding the stack
            throw lue;
         }
         
         catch (NextUnwindException nue)
         {
            if (testNext(wa, enclosing, "catchBlock") == Disposition.BREAK)
            {
               // the NEXT can't be targeted at this block BUT it can be
               // targeted at an enclosing non-managed block
               break blockLabel;
            }
            
            // the NEXT must be referencing an enclosing block which IS
            // known to the block manager OR to one of the other enclosing
            // managed blocks, so keep unwinding the stack
            throw nue;
         }
         
         catch (ReturnUnwindException rue)
         {
            // RETURN can't be targeted at a DO block so keep unwinding
            throw rue;
         }
            
         catch (Throwable thr)
         {
            wa.tm.abnormalEnd(thr);
         }
      }
      
      finally
      {
         wa.tm.popScope();
      }
   }

   /**
    * The CATCH statement.  This API must be called from the Block's init method, and it will
    * register a listener for the specified legacy error.
    * <p>
    * The catch order is the order of this API registration calls.
    * 
    * @param    type
    *           The CATCH's error type.
    * @param    catchBlock
    *           The code to be executed for this error.
    */
   public static <T extends LegacyError> void catchError(Class<T>            type,
                                                         Consumer<object<T>> catchBlock)
   {
      registerCatchBlock(type, catchBlock);
   }
   
   /**
    * The CATCH statement.  This API must be called from the Block's init method, and it will
    * register a listener for the specified STOP condition.
    * <p>
    * The catch order is the order of this API registration calls.
    * 
    * @param    type
    *           The CATCH's stop error type.
    * @param    catchBlock
    *           The code to be executed for this error.
    */
   public static <T extends Stop> void catchStop(Class<T>            type,
                                                 Consumer<object<T>> catchBlock)
   {
      registerCatchBlock(type, catchBlock);
   }
   
   /**
    * Execute the given catch block as if it was a simple DO block.
    *
    * @param    body
    *           The catch block to execute.
    */
   public static void processCatch(Body body)
   {
      doBlock("_catch_block_", new Block(body));
   }
   
   /**
    * Trigger a rollback of the current block and then throw a legacy condition.
    * 
    * @param    error
    *           The legacy error to throw.
    */
   public static void undoThrowTopLevel(object<? extends LegacyError> error)
   {
      if (!error._isValid())
      {
         String[] texts =
         {
            "You can only use a valid object reference in an UNDO, THROW or RETURN ERROR " + 
            "statement and it must be a class that implements Progress.Lang.Error",
            "THROW statement failed"
         };
         int[] nums = {14117, 14456};
         
         ErrorManager.recordOrThrowError(nums, texts, false, false);
         return;
      }

      WorkArea wa = work.get();
      
      BlockDefinition blk = wa.tm.getBlock();
      if (blk.type == BlockType.CATCH)
      {
         // UNDO, THROW in a CATCH for a top-level block is emitted as 'undoThrowTopLevel'. 
         // but the behavior must be undoThrow.
         undoThrow(error);
         return;
      }

      wa.tm.rollbackTopLevel();

      boolean fromReturn = setReturnValue(wa, error.ref);
      LegacyErrorException lex = new LegacyErrorException(error, fromReturn);
      lex.setExplicit(true);
      
      // only RETURN ERROR is raised on the caller's side for an appserver call.
      if (mustManageLegacyError(wa) && !(AppServerManager.isRemote() && !fromReturn))
      {
         wa.tm.triggerErrorInCaller(lex);
      }
      
      displayErrorMessages(wa.tm, lex.getErrorRef(), false, false);
      
      throw lex;
   }
   
   /**
    * Trigger a rollback of the current block and then throw a legacy STOP condition.
    * 
    * @param    stopError
    *           The legacy STOP error to throw.
    */
   public static void undoThrowStopTopLevel(object<? extends Stop> stopError)
   {
      if (!stopError._isValid())
      {
         String[] texts =
         {
            "You can only use a valid object reference in an UNDO, THROW or RETURN" + 
            "statement and it must be a class that implements Progress.Lang.Stop",
            "THROW statement failed"
         };
         int[] nums = {14117, 14456};
         
         ErrorManager.recordOrThrowError(nums, texts, false, false);
         return;
      }

      WorkArea wa = work.get();
      
      BlockDefinition blk = wa.tm.getBlock();
      if (blk.type == BlockType.CATCH)
      {
         // UNDO, THROW in a CATCH for a top-level block is emitted as 'undoThrowStopTopLevel'. 
         // but the behavior must be undoThrow.
         undoThrowStop(stopError);
         return;
      }

      wa.tm.rollbackTopLevel();
      ErrorManager.handleStopException(stopError);
   }
   
   /**
    * Trigger a rollback of the current block and then throw a legacy condition.
    * 
    * @param    error
    *           The legacy error to throw.
    */
   public static void undoThrow(object<? extends LegacyError> error)
   {
      if (!error._isValid())
      {
         String[] texts =
         {
            "You can only use a valid object reference in an UNDO, THROW or RETURN ERROR " + 
            "statement and it must be a class that implements Progress.Lang.Error",
            "THROW statement failed"
         };
         int[] nums = {14117, 14456};
         
         ErrorManager.recordOrThrowError(nums, texts, false, false);
         return;
      }

      WorkArea wa = work.obtain();

      // TODO: any other processing?
      setReturnValue(wa, error.ref);

      if (!ErrorManager.hasLegacyError())
      {
         displayErrorMessages(wa.tm, error.ref, false, true);
      }
      
      LegacyErrorException lex = new LegacyErrorException(error);
      lex.setExplicit(true);
      throw lex;
   }
   
   /**
    * Trigger a rollback of the current block and then throw a legacy STOP condition.
    * 
    * @param    stopError
    *           The legacy STOP error to throw.
    */
   public static void undoThrowStop(object<? extends Stop> stopError)
   {
      if (!stopError._isValid())
      {
         String[] texts =
         {
            "You can only use a valid object reference in an UNDO, THROW" + 
            "statement and it must be a class that implements Progress.Lang.Stop",
            "THROW statement failed"
         };
         int[] nums = {14117, 14456};
         
         ErrorManager.recordOrThrowError(nums, texts, false, false);
         return;
      }
      
      ErrorManager.handleStopException(stopError);
   }
   
   /**
    * Trigger a rollback of the current block and then leave that block.
    * 
    * @throws   LeaveUnwindException 
    */
   public static void undoLeave()
   throws LeaveUnwindException
   {
      undoLeave(null, "");
   }
   
   /**
    * Trigger a rollback of the given block and then leave that block.
    *
    * @param    label
    *           The name of the block that is the target of the undo and
    *           leave operations.
    * 
    * @throws   LeaveUnwindException 
    */
   public static void undoLeave(String label)
   throws LeaveUnwindException
   {
      undoLeave(label, label);
   }
   
   /**
    * Trigger a rollback of the given block and then leave that block or a
    * more enclosing block.
    * <p>
    * If the current block is a variant of a FOR block, then the buffers
    * associated with the block's query must not change the referenced 
    * record.
    *
    * @param    undo
    *           The name of the block that is the target of the undo
    *           operation.
    * @param    leave
    *           The name of the block that is the target of the leave
    *           operation.
    * 
    * @throws   LeaveUnwindException 
    */
   public static void undoLeave(String undo, String leave)
   throws LeaveUnwindException
   {
      WorkArea wa = work.obtain();
      
      BlockType blk = wa.tm.getBlockType();
      
      boolean forBlock = blk == BlockType.FOR_BLOCK          ||
                         blk == BlockType.FOR_BLOCK_WHILE    ||
                         blk == BlockType.FOR_BLOCK_TO       ||
                         blk == BlockType.FOR_BLOCK_TO_WHILE ||
                         blk == BlockType.FOR_LOOP           ||
                         blk == BlockType.FOR_LOOP_WHILE     ||
                         blk == BlockType.FOR_LOOP_TO        ||
                         blk == BlockType.FOR_LOOP_TO_WHILE;
      
      try
      {
         if (forBlock)
         {
            wa.tm.processOffEndListeners(true);
         }

         wa.tm.rollback(undo);
         leave(wa, leave);
      }
      finally
      {
         if (forBlock)
         {
            wa.tm.processOffEndListeners(false);
         }
      }
   }
   
   /**
    * Trigger a rollback of the current block and then iterate that block.
    * <p>
    * Infinite loop protection may convert the NEXT action into a LEAVE
    * depending on runtime state.
    * 
    * @throws   NextUnwindException 
    */
   public static void undoNext()
   throws NextUnwindException
   {
      undoNext(null, "");
   }
   
   /**
    * Trigger a rollback of the given block and then iterate that block.
    * <p>
    * Infinite loop protection may convert the NEXT action into a LEAVE
    * depending on runtime state.
    *
    * @param    label
    *           The name of the block that is the target of the undo and
    *           next operations.
    * 
    * @throws   NextUnwindException 
    */
   public static void undoNext(String label)
   throws NextUnwindException
   {
      undoNext(label, label);
   }
   
   /**
    * Trigger a rollback of the given block and then iterate that block or
    * a more enclosing block.
    * <p>
    * Infinite loop protection may convert the NEXT action into a LEAVE
    * depending on runtime state.
    *
    * @param    undo
    *           The name of the block that is the target of the undo
    *           operation.
    * @param    next
    *           The name of the block that is the target of the next
    *           operation.
    * 
    * @throws   NextUnwindException 
    */
   public static void undoNext(String undo, String next)
   throws NextUnwindException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollback(undo);
      
      if (wa.tm.honorNext(next))
      {
         next(wa, next);
      }
      else
      {
         leave(wa, next);
      }
   }
   
   /**
    * Trigger a rollback of the current block and then retry that block.
    * 
    * @throws   RetryUnwindException 
    */
   public static void undoRetry()
   throws RetryUnwindException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollback();
      wa.tm.forceRetry(null);
   }
   
   /**
    * Trigger a rollback of the given block and then retry that block.
    *
    * @param    label
    *           The name of the block that is the target of the undo and
    *           retry operations.
    * 
    * @throws   RetryUnwindException 
    */
   public static void undoRetry(String label)
   throws RetryUnwindException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollback(label);
      wa.tm.forceRetry(label);
   }
   
   /**
    * Trigger a rollback of the nearest enclosing top-level block and then
    * retry that block.
    * 
    * @throws   RetryUnwindException 
    */
   public static void undoRetryTopLevel()
   throws RetryUnwindException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollbackTopLevel();
      wa.tm.forceRetry(null);
   }
   
   /**
    * Trigger a rollback of the current block and then return from the nearest
    * enclosing top-level block. Sets the default <code>RETURN-VALUE</code> to
    * "" (empty string) for internal/external procedures and triggers. Leaves
    * <code>unknown value</code> as the default return from a user-defined
    * function.
    * 
    * @throws   ReturnUnwindException 
    */
   public static void undoReturnNormal()
   throws ReturnUnwindException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollback();
      returnWorker(wa, null, ReturnType.NORMAL);
   }
   
   /**
    * Trigger a rollback and then return from the nearest enclosing top-level
    * block. Sets the default <code>RETURN-VALUE</code> to "" (empty string)
    * for internal/external procedures and triggers. Leaves
    * <code>unknown value</code> as the default return from a user-defined
    * function.
    * 
    * @throws   ReturnUnwindException 
    */
   public static void undoReturnNormalTopLevel()
   throws ReturnUnwindException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollbackTopLevel();
      returnWorker(wa, null, ReturnType.NORMAL);
   }
   
   /**
    * Trigger a rollback of the given block and then return from the nearest
    * enclosing top-level block. Sets the default <code>RETURN-VALUE</code> to
    * "" (empty string) for internal/external procedures and triggers. Leaves
    * <code>unknown value</code> as the default return from a user-defined
    * function.
    *
    * @param    label
    *           The name of the block that is the target of the undo
    *           operation.
    * 
    * @throws   ReturnUnwindException 
    */
   public static void undoReturnNormal(String label)
   throws ReturnUnwindException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollback(label);
      returnWorker(wa, null, ReturnType.NORMAL);
   }
   
   /**
    * Trigger a rollback of the current block and then return from the nearest
    * enclosing top-level block. Sets the <code>RETURN-VALUE</code> to the
    * given <code>character</code> value for internal/external procedures and
    * triggers. Saves the given value as the return value for a user-defined
    * function.  If <code>val</code> is <code>null</code>, then
    * <code>RETURN-VALUE</code> will be set to the "" (empty string) for
    * internal/external procedures and triggers. If <code>val</code> is
    * <code>null</code> for a user-defined function,
    * <code>unknown value</code> will be the default return.
    *
    * @param    val
    *           The value to return or <code>null</code>.  For procedures
    *           or triggers, this must be a <code>character</code> value.
    * 
    * @throws   ReturnUnwindException 
    */
   public static void undoReturnNormal(BaseDataType val)
   throws ReturnUnwindException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollback();
      returnWorker(wa, val, ReturnType.NORMAL);
   }
   
   /**
    * Trigger a rollback of the nearest enclosing top-level block and then
    * return from that block. Sets the <code>RETURN-VALUE</code> to the
    * given <code>character</code> value for internal/external procedures and
    * triggers. Saves the given value as the return value for a user-defined
    * function.  If <code>val</code> is <code>null</code>, then
    * <code>RETURN-VALUE</code> will be set to the "" (empty string) for
    * internal/external procedures and triggers. If <code>val</code> is
    * <code>null</code> for a user-defined function,
    * <code>unknown value</code> will be the default return.
    *
    * @param    val
    *           The value to return or <code>null</code>.  For procedures
    *           or triggers, this must be a <code>character</code> value.
    * 
    * @throws   ReturnUnwindException 
    */
   public static void undoReturnNormalTopLevel(BaseDataType val)
   throws ReturnUnwindException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollbackTopLevel();
      returnWorker(wa, val, ReturnType.NORMAL);
   }
   
   /**
    * Trigger a rollback of the given block and then return from the nearest
    * enclosing top-level block. Sets the <code>RETURN-VALUE</code> to the
    * given <code>character</code> value for internal/external procedures and
    * triggers. Saves the given value as the return value for a user-defined
    * function.  If <code>val</code> is <code>null</code>, then
    * <code>RETURN-VALUE</code> will be set to the "" (empty string) for
    * internal/external procedures and triggers. If <code>val</code> is
    * <code>null</code> for a user-defined function,
    * <code>unknown value</code> will be the default return.
    *
    * @param    label
    *           The name of the block that is the target of the undo
    *           operation.
    * @param    val
    *           The value to return or <code>null</code>.  For procedures
    *           or triggers, this must be a <code>character</code> value.
    * 
    * @throws   ReturnUnwindException 
    */
   public static void undoReturnNormal(String label, BaseDataType val)
   throws ReturnUnwindException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollback(label);
      returnWorker(wa, val, ReturnType.NORMAL);
   }
   
   /**
    * Trigger a rollback of the given block and then return from the nearest
    * enclosing top-level block. Sets the <code>RETURN-VALUE</code> to the
    * given <code>character</code> value for internal/external procedures and
    * triggers. Saves the given value as the return value for a user-defined
    * function.  If <code>val</code> is <code>null</code>, then
    * <code>RETURN-VALUE</code> will be set to the "" (empty string) for
    * internal/external procedures and triggers. If <code>val</code> is
    * <code>null</code> for a user-defined function,
    * <code>unknown value</code> will be the default return.
    *
    * @param    label
    *           The name of the block that is the target of the undo
    *           operation.
    * @param    val
    *           The value to return or <code>null</code>.
    * 
    * @throws   ReturnUnwindException 
    */
   public static void undoReturnNormal(String label, String val)
   throws ReturnUnwindException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollback(label);
      returnWorker(wa, new character(val), ReturnType.NORMAL);
   }
   
   /**
    * Trigger a rollback of the nearest enclosing top-level block and then
    * return from that block. Sets the <code>RETURN-VALUE</code> to the
    * given <code>character</code> value for internal/external procedures and
    * triggers. Saves the given value as the return value for a user-defined
    * function.  If <code>val</code> is <code>null</code>, then
    * <code>RETURN-VALUE</code> will be set to the "" (empty string) for
    * internal/external procedures and triggers. If <code>val</code> is
    * <code>null</code> for a user-defined function,
    * <code>unknown value</code> will be the default return.
    *
    * @param    val
    *           The value to return or <code>null</code>.  For procedures
    *           or triggers, this must be a <code>character</code> value.
    * 
    * @throws   ReturnUnwindException 
    */
   public static void undoReturnNormalTopLevel(String val)
   throws ReturnUnwindException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollbackTopLevel();
      returnWorker(wa, new character(val), ReturnType.NORMAL);
   }
   
   /**
    * Trigger a rollback of the current block and then return from the nearest
    * enclosing top-level block. This should not be used for internal/external
    * procedures and triggers, since the <code>RETURN-VALUE</code> can only be
    * set to a character expression.
    * <p>
    * For a user-defined function, this saves the given value as the function
    * return value.
    *
    * @param    val
    *           The value to return.
    * 
    * @throws   ReturnUnwindException 
    */
   public static void undoReturnNormal(int val)
   throws ReturnUnwindException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollback();
      returnWorker(wa, new integer(val), ReturnType.NORMAL);
   }
   
   /**
    * Trigger a rollback of the nearest enclosing top-level block and then
    * return from that block. Sets the <code>RETURN-VALUE</code> to the
    * given <code>character</code> value for internal/external procedures and
    * triggers. Saves the given value as the return value for a user-defined
    * function.  If <code>val</code> is <code>null</code>, then
    * <code>RETURN-VALUE</code> will be set to the "" (empty string) for
    * internal/external procedures and triggers. If <code>val</code> is
    * <code>null</code> for a user-defined function,
    * <code>unknown value</code> will be the default return.
    *
    * @param    val
    *           The value to return.
    * 
    * @throws   ReturnUnwindException 
    */
   public static void undoReturnNormalTopLevel(int val)
   throws ReturnUnwindException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollbackTopLevel();
      returnWorker(wa, new integer(val), ReturnType.NORMAL);
   }
   
   /**
    * Trigger a rollback of the given block and then return from the nearest
    * enclosing top-level block. This should not be used for internal/external
    * procedures and triggers, since the <code>RETURN-VALUE</code> can only be
    * set to a character expression.
    * <p>
    * For a user-defined function, this saves the given value as the function
    * return value.
    *
    * @param    label
    *           The name of the block that is the target of the undo
    *           operation.
    * @param    val
    *           The value to return.
    * 
    * @throws   ReturnUnwindException 
    */
   public static void undoReturnNormal(String label, int val)
   throws ReturnUnwindException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollback(label);
      returnWorker(wa, new integer(val), ReturnType.NORMAL);
   }
   
   /**
    * Trigger a rollback of the current block and then return from the nearest
    * enclosing top-level block. This should not be used for internal/external
    * procedures and triggers, since the <code>RETURN-VALUE</code> can only be
    * set to a character expression.
    * <p>
    * For a user-defined function, this saves the given value as the function
    * return value.
    *
    * @param    val
    *           The value to return.
    * 
    * @throws   ReturnUnwindException 
    */
   public static void undoReturnNormal(double val)
   throws ReturnUnwindException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollback();
      returnWorker(wa, new decimal(val), ReturnType.NORMAL);
   }
   
   /**
    * Trigger a rollback of the nearest enclosing top-level block and then
    * return from that block. Sets the <code>RETURN-VALUE</code> to the
    * given <code>character</code> value for internal/external procedures and
    * triggers. Saves the given value as the return value for a user-defined
    * function.  If <code>val</code> is <code>null</code>, then
    * <code>RETURN-VALUE</code> will be set to the "" (empty string) for
    * internal/external procedures and triggers. If <code>val</code> is
    * <code>null</code> for a user-defined function,
    * <code>unknown value</code> will be the default return.
    *
    * @param    val
    *           The value to return.
    * 
    * @throws   ReturnUnwindException 
    */
   public static void undoReturnNormalTopLevel(double val)
   throws ReturnUnwindException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollbackTopLevel();
      returnWorker(wa, new decimal(val), ReturnType.NORMAL);
   }
   
   /**
    * Trigger a rollback of the given block and then return from the nearest
    * enclosing top-level block. This should not be used for internal/external
    * procedures and triggers, since the <code>RETURN-VALUE</code> can only be
    * set to a character expression.
    * <p>
    * For a user-defined function, this saves the given value as the function
    * return value.
    *
    * @param    label
    *           The name of the block that is the target of the undo
    *           operation.
    * @param    val
    *           The value to return.
    * 
    * @throws   ReturnUnwindException 
    */
   public static void undoReturnNormal(String label, double val)
   throws ReturnUnwindException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollback(label);
      returnWorker(wa, new decimal(val), ReturnType.NORMAL);
   }
   
   /**
    * Trigger a rollback of the current block and then return from the nearest
    * enclosing top-level block. This should not be used for internal/external
    * procedures and triggers, since the <code>RETURN-VALUE</code> can only be
    * set to a character expression.
    * <p>
    * For a user-defined function, this saves the given value as the function
    * return value.
    *
    * @param    val
    *           The value to return.
    * 
    * @throws   ReturnUnwindException 
    */
   public static void undoReturnNormal(boolean val)
   throws ReturnUnwindException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollback();
      returnWorker(wa, logical.of(val), ReturnType.NORMAL);
   }
   
   /**
    * Trigger a rollback of the nearest enclosing top-level block and then
    * return from that block. Sets the <code>RETURN-VALUE</code> to the
    * given <code>character</code> value for internal/external procedures and
    * triggers. Saves the given value as the return value for a user-defined
    * function.  If <code>val</code> is <code>null</code>, then
    * <code>RETURN-VALUE</code> will be set to the "" (empty string) for
    * internal/external procedures and triggers. If <code>val</code> is
    * <code>null</code> for a user-defined function,
    * <code>unknown value</code> will be the default return.
    *
    * @param    val
    *           The value to return.
    * 
    * @throws   ReturnUnwindException 
    */
   public static void undoReturnNormalTopLevel(boolean val)
   throws ReturnUnwindException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollbackTopLevel();
      returnWorker(wa, logical.of(val), ReturnType.NORMAL);
   }
   
   /**
    * Trigger a rollback of the given block and then return from the nearest
    * enclosing top-level block. This should not be used for internal/external
    * procedures and triggers, since the <code>RETURN-VALUE</code> can only be
    * set to a character expression.
    * <p>
    * For a user-defined function, this saves the given value as the function
    * return value.
    *
    * @param    label
    *           The name of the block that is the target of the undo
    *           operation.
    * @param    val
    *           The value to return.
    * 
    * @throws   ReturnUnwindException 
    */
   public static void undoReturnNormal(String label, boolean val)
   throws ReturnUnwindException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollback(label);
      returnWorker(wa, logical.of(val), ReturnType.NORMAL);
   }
   
   /**
    * Trigger a rollback of the current block and then return from the nearest
    * enclosing top-level block. Sets the default <code>RETURN-VALUE</code>
    * to "" (empty string) for internal/external procedures and triggers.
    * Leaves <code>unknown value</code> as the default return from a
    * user-defined function.
    * <p>
    * If executed for a trigger, force the event which caused the trigger
    * execution to be consumed (no default processing of that event should
    * occur).
    * 
    * @throws   ReturnUnwindException 
    */
   public static void undoReturnConsume()
   throws ReturnUnwindException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollback();
      returnWorker(wa, null, ReturnType.CONSUME);
   }
   
   /**
    * Trigger a rollback of and then return from the nearest
    * enclosing top-level block. Sets the default <code>RETURN-VALUE</code>
    * to "" (empty string) for internal/external procedures and triggers.
    * Leaves <code>unknown value</code> as the default return from a
    * user-defined function.
    * <p>
    * If executed for a trigger, force the event which caused the trigger
    * execution to be consumed (no default processing of that event should
    * occur).
    * 
    * @throws   ReturnUnwindException 
    */
   public static void undoReturnConsumeTopLevel()
   throws ReturnUnwindException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollbackTopLevel();
      returnWorker(wa, null, ReturnType.CONSUME);
   }
   
   /**
    * Trigger a rollback of the current block and then return from the nearest
    * enclosing top-level block, consuming any pending event processing. Sets
    * the <code>RETURN-VALUE</code> to the given value for internal/external
    * procedures and triggers. Should not be called for a user-defined
    * function.
    * <p>
    * If executed for a trigger, force the event which caused the trigger
    * execution to be consumed (no default processing of that event should
    * occur).
    *
    * @param    val
    *           The value to return or <code>null</code>.
    * 
    * @throws   ReturnUnwindException 
    */
   public static void undoReturnConsume(character val)
   throws ReturnUnwindException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollback();
      returnWorker(wa, val, ReturnType.CONSUME);
   }
   
   /**
    * Trigger a rollback of and then return from the nearest
    * enclosing top-level block, consuming any pending event processing. Sets
    * the <code>RETURN-VALUE</code> to the given value for internal/external
    * procedures and triggers. Should not be called for a user-defined
    * function.
    * <p>
    * If executed for a trigger, force the event which caused the trigger
    * execution to be consumed (no default processing of that event should
    * occur).
    *
    * @param    val
    *           The value to return or <code>null</code>.
    * 
    * @throws   ReturnUnwindException 
    */
   public static void undoReturnConsumeTopLevel(character val)
   throws ReturnUnwindException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollbackTopLevel();
      returnWorker(wa, val, ReturnType.CONSUME);
   }
   
   /**
    * Trigger a rollback of the given block and then return from the nearest
    * enclosing top-level block. Sets the default <code>RETURN-VALUE</code>
    * to "" (empty string) for internal/external procedures and triggers.
    * Leaves <code>unknown value</code> as the default return from a
    * user-defined function.
    * <p>
    * If executed for a trigger, force the event which caused the trigger
    * execution to be consumed (no default processing of that event should
    * occur).
    *
    * @param    label
    *           The name of the block that is the target of the undo
    *           operation.
    * 
    * @throws   ReturnUnwindException 
    */
   public static void undoReturnConsume(String label)
   throws ReturnUnwindException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollback(label);
      returnWorker(wa, null, ReturnType.CONSUME);
   }
   
   /**
    * Trigger a rollback of the given block and then return from the nearest
    * enclosing top-level block, consuming any pending event processing. Sets
    * the <code>RETURN-VALUE</code> to the given value for internal/external
    * procedures and triggers. Should not be called for a user-defined
    * function.
    * <p>
    * If executed for a trigger, force the event which caused the trigger
    * execution to be consumed (no default processing of that event should
    * occur).
    *
    * @param    label
    *           The name of the block that is the target of the undo
    *           operation.
    * @param    val
    *           The value to return or <code>null</code>.
    * 
    * @throws   ReturnUnwindException 
    */
   public static void undoReturnConsume(String label, character val)
   throws ReturnUnwindException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollback(label);
      returnWorker(wa, val, ReturnType.CONSUME);
   }
   
   /**
    * Trigger a rollback of the given block and then return from the nearest
    * enclosing top-level block, consuming any pending event processing. Sets
    * the <code>RETURN-VALUE</code> to the given value for internal/external
    * procedures and triggers. Should not be called for a user-defined
    * function.
    * <p>
    * If executed for a trigger, force the event which caused the trigger
    * execution to be consumed (no default processing of that event should
    * occur).
    *
    * @param    label
    *           The name of the block that is the target of the undo
    *           operation.
    * @param    val
    *           The value to return or <code>null</code>.
    * 
    * @throws   ReturnUnwindException 
    */
   public static void undoReturnConsume(String label, String val)
   throws ReturnUnwindException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollback(label);
      returnWorker(wa, new character(val), ReturnType.CONSUME);
   }
   
   /**
    * Trigger a rollback of and then return from the nearest
    * enclosing top-level block, consuming any pending event processing. Sets
    * the <code>RETURN-VALUE</code> to the given value for internal/external
    * procedures and triggers. Should not be called for a user-defined
    * function.
    * <p>
    * If executed for a trigger, force the event which caused the trigger
    * execution to be consumed (no default processing of that event should
    * occur).
    *
    * @param    val
    *           The value to return or <code>null</code>.
    * 
    * @throws   ReturnUnwindException 
    */
   public static void undoReturnConsumeTopLevel(String val)
   throws ReturnUnwindException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollbackTopLevel();
      returnWorker(wa, new character(val), ReturnType.CONSUME);
   }
   
   /**
    * Trigger a rollback of the current block and then return from the nearest
    * enclosing top-level block. Sets the default <code>RETURN-VALUE</code>
    * to "" (empty string) for internal/external procedures and triggers.
    * Leaves <code>unknown value</code> as the default return from a
    * user-defined function.
    * <p>
    * If silent error mode is not enabled in the caller, an <code>ERROR</code>
    * condition will be raised here and will unwind the stack (it will not
    * be processed, but will instead it will be rethrown) until it reaches
    * the caller's context at which time the error will be honored. If silent
    * error mode is enabled, the error data will be stored in the 
    * <code>ERROR-STATUS</code> facility and a return will be executed to
    * return processing to the caller without raising the error condition
    * (without throwing an exception).
    * 
    * @throws   ReturnUnwindException 
    * @throws   ErrorConditionException 
    */
   public static void undoReturnError()
   throws ReturnUnwindException,
          ErrorConditionException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollback();
      returnWorker(wa, null, ReturnType.ERROR);
   }
   
   /**
    * Trigger a rollback of and then return from the nearest
    * enclosing top-level block. Sets the default <code>RETURN-VALUE</code>
    * to "" (empty string) for internal/external procedures and triggers.
    * Leaves <code>unknown value</code> as the default return from a
    * user-defined function.
    * <p>
    * If silent error mode is not enabled in the caller, an <code>ERROR</code>
    * condition will be raised here and will unwind the stack (it will not
    * be processed, but will instead it will be rethrown) until it reaches
    * the caller's context at which time the error will be honored. If silent
    * error mode is enabled, the error data will be stored in the 
    * <code>ERROR-STATUS</code> facility and a return will be executed to
    * return processing to the caller without raising the error condition
    * (without throwing an exception).
    * 
    * @throws   ReturnUnwindException 
    * @throws   ErrorConditionException 
    */
   public static void undoReturnErrorTopLevel()
   throws ReturnUnwindException,
          ErrorConditionException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollbackTopLevel();
      returnWorker(wa, null, ReturnType.ERROR);
   }
   
   /**
    * Trigger a rollback of the given block and then return from the nearest
    * enclosing top-level block. Sets the default <code>RETURN-VALUE</code>
    * to "" (empty string) for internal/external procedures and triggers.
    * Leaves <code>unknown value</code> as the default return from a
    * user-defined function.
    * <p>
    * If silent error mode is not enabled in the caller, an <code>ERROR</code>
    * condition will be raised here and will unwind the stack (it will not
    * be processed, but will instead it will be rethrown) until it reaches
    * the caller's context at which time the error will be honored. If silent
    * error mode is enabled, the error data will be stored in the 
    * <code>ERROR-STATUS</code> facility and a return will be executed to
    * return processing to the caller without raising the error condition
    * (without throwing an exception).
    *
    * @param    label
    *           The name of the block that is the target of the undo
    *           operation.
    * 
    * @throws   ReturnUnwindException 
    * @throws   ErrorConditionException 
    */
   public static void undoReturnError(String label)
   throws ReturnUnwindException,
          ErrorConditionException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollback(label);
      returnWorker(wa, null, ReturnType.ERROR);
   }
   
   /**
    * Trigger a rollback of the current block and then return from the nearest
    * enclosing top-level block. If the given value is <code>null</code>,
    * this sets the default <code>RETURN-VALUE</code> to "" (empty string)
    * for internal/external procedures and triggers. It leaves
    * <code>unknown value</code> as the default return from a user-defined
    * function.  If the value is not <code>null</code>, then that value (if
    * it is a <code>character</code> type) will be set as the
    * <code>RETURN-VALUE</code> for internal/external procedures and triggers.
    * If not <code>null</code>, the value will be returned as the function
    * return value for user-defined functions.
    * <p>
    * If silent error mode is not enabled in the caller, an <code>ERROR</code>
    * condition will be raised here and will unwind the stack (it will not
    * be processed, but will instead it will be rethrown) until it reaches
    * the caller's context at which time the error will be honored. If silent
    * error mode is enabled, the error data will be stored in the 
    * <code>ERROR-STATUS</code> facility and a return will be executed to
    * return processing to the caller without raising the error condition
    * (without throwing an exception).
    *
    * @param    val
    *           The value to return.
    * 
    * @throws   ReturnUnwindException 
    * @throws   ErrorConditionException 
    */
   public static void undoReturnError(character val)
   throws ReturnUnwindException,
          ErrorConditionException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollback();
      returnWorker(wa, val, ReturnType.ERROR);
   }
   
   /**
    * Trigger a rollback of and then return from the nearest
    * enclosing top-level block. If the given value is <code>null</code>,
    * this sets the default <code>RETURN-VALUE</code> to "" (empty string)
    * for internal/external procedures and triggers. It leaves
    * <code>unknown value</code> as the default return from a user-defined
    * function.  If the value is not <code>null</code>, then that value (if
    * it is a <code>character</code> type) will be set as the
    * <code>RETURN-VALUE</code> for internal/external procedures and triggers.
    * If not <code>null</code>, the value will be returned as the function
    * return value for user-defined functions.
    * <p>
    * If silent error mode is not enabled in the caller, an <code>ERROR</code>
    * condition will be raised here and will unwind the stack (it will not
    * be processed, but will instead it will be rethrown) until it reaches
    * the caller's context at which time the error will be honored. If silent
    * error mode is enabled, the error data will be stored in the 
    * <code>ERROR-STATUS</code> facility and a return will be executed to
    * return processing to the caller without raising the error condition
    * (without throwing an exception).
    *
    * @param    val
    *           The value to return.
    * 
    * @throws   ReturnUnwindException 
    * @throws   ErrorConditionException 
    */
   public static void undoReturnErrorTopLevel(character val)
   throws ReturnUnwindException,
          ErrorConditionException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollbackTopLevel();
      returnWorker(wa, val, ReturnType.ERROR);
   }
   
   /**
    * Trigger a rollback of the given block and then return from the nearest
    * enclosing top-level block. If the given value is <code>null</code>,
    * this sets the default <code>RETURN-VALUE</code> to "" (empty string)
    * for internal/external procedures and triggers. It leaves
    * <code>unknown value</code> as the default return from a user-defined
    * function.  If the value is not <code>null</code>, then that value (if
    * it is a <code>character</code> type) will be set as the
    * <code>RETURN-VALUE</code> for internal/external procedures and triggers.
    * If not <code>null</code>, the value will be returned as the function
    * return value for user-defined functions.
    * <p>
    * If silent error mode is not enabled in the caller, an <code>ERROR</code>
    * condition will be raised here and will unwind the stack (it will not
    * be processed, but will instead it will be rethrown) until it reaches
    * the caller's context at which time the error will be honored. If silent
    * error mode is enabled, the error data will be stored in the 
    * <code>ERROR-STATUS</code> facility and a return will be executed to
    * return processing to the caller without raising the error condition
    * (without throwing an exception).
    *
    * @param    label
    *           The name of the block that is the target of the undo
    *           operation.
    * @param    val
    *           The value to return.
    * 
    * @throws   ReturnUnwindException 
    * @throws   ErrorConditionException 
    */
   public static void undoReturnError(String label, character val)
   throws ReturnUnwindException,
          ErrorConditionException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollback(label);
      returnWorker(wa, val, ReturnType.ERROR);
   }
   
   /**
    * Trigger a rollback of the given block and then return from the nearest
    * enclosing top-level block. If the given value is <code>null</code>,
    * this sets the default <code>RETURN-VALUE</code> to "" (empty string)
    * for internal/external procedures and triggers. It leaves
    * <code>unknown value</code> as the default return from a user-defined
    * function.  If the value is not <code>null</code>, then that value (if
    * it is a <code>character</code> type) will be set as the
    * <code>RETURN-VALUE</code> for internal/external procedures and triggers.
    * If not <code>null</code>, the value will be returned as the function
    * return value for user-defined functions.
    * <p>
    * If silent error mode is not enabled in the caller, an <code>ERROR</code>
    * condition will be raised here and will unwind the stack (it will not
    * be processed, but will instead it will be rethrown) until it reaches
    * the caller's context at which time the error will be honored. If silent
    * error mode is enabled, the error data will be stored in the 
    * <code>ERROR-STATUS</code> facility and a return will be executed to
    * return processing to the caller without raising the error condition
    * (without throwing an exception).
    *
    * @param    label
    *           The name of the block that is the target of the undo
    *           operation.
    * @param    val
    *           The value to return.
    * 
    * @throws   ReturnUnwindException 
    * @throws   ErrorConditionException 
    */
   public static void undoReturnError(String label, String val)
   throws ReturnUnwindException,
          ErrorConditionException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollback(label);
      returnWorker(wa, new character(val), ReturnType.ERROR);
   }
   
   /**
    * Trigger a rollback of and then return from the nearest
    * enclosing top-level block. If the given value is <code>null</code>,
    * this sets the default <code>RETURN-VALUE</code> to "" (empty string)
    * for internal/external procedures and triggers. It leaves
    * <code>unknown value</code> as the default return from a user-defined
    * function.  If the value is not <code>null</code>, then that value (if
    * it is a <code>character</code> type) will be set as the
    * <code>RETURN-VALUE</code> for internal/external procedures and triggers.
    * If not <code>null</code>, the value will be returned as the function
    * return value for user-defined functions.
    * <p>
    * If silent error mode is not enabled in the caller, an <code>ERROR</code>
    * condition will be raised here and will unwind the stack (it will not
    * be processed, but will instead it will be rethrown) until it reaches
    * the caller's context at which time the error will be honored. If silent
    * error mode is enabled, the error data will be stored in the 
    * <code>ERROR-STATUS</code> facility and a return will be executed to
    * return processing to the caller without raising the error condition
    * (without throwing an exception).
    *
    * @param    val
    *           The value to return.
    * 
    * @throws   ReturnUnwindException 
    * @throws   ErrorConditionException 
    */
   public static void undoReturnErrorTopLevel(String val)
   throws ReturnUnwindException,
          ErrorConditionException
   {
      WorkArea wa = work.obtain();
      
      wa.tm.rollbackTopLevel();
      returnWorker(wa, new character(val), ReturnType.ERROR);
   }
   
   /**
    * Check if the top-level block is ROUTINE-LEVEL UNDO, THROW or the current program is 
    * BLOCK-LEVEL UNDO, THROW.
    * 
    * @return  see above.
    */
   static boolean mustManageLegacyError()
   {
      return mustManageLegacyError(work.obtain());
   }
   
   /**
    * Check if the top-level block is ROUTINE-LEVEL UNDO, THROW or the current program is 
    * BLOCK-LEVEL UNDO, THROW.
    *
    * @param   wa
    *          The {@link WorkArea} instance.
    * @param   forceBlockLevelUndoThrow
    *          Flag indicating that, when nothing else matches, a BLOCK-LEVEL UNDO, THROW exists by default.
    *          
    * @return  see above.
    */
   static boolean mustManageLegacyError(WorkArea wa, boolean forceBlockLevelUndoThrow)
   {
      return wa.pm._thisProcedure() != null && 
            (forceBlockLevelUndoThrow ||
             (wa.tm.isRootNestingLevel() && AppServerManager.isRemote() && wa.pm.isRoutineLevelUndoThrow()) || 
             (wa.tm.isTopLevelBlock() && wa.pm.isRoutineLevelUndoThrow())                                   || 
             wa.pm.isBlockLevelUndoThrow());
   }   
   /**
    * Check if the top-level block is ROUTINE-LEVEL UNDO, THROW or the current program is 
    * BLOCK-LEVEL UNDO, THROW.
    * 
    * @param   forceBlockLevelUndoThrow
    *          Flag indicating that, when nothing else matches, a BLOCK-LEVEL UNDO, THROW exists by default.
    * 
    * @return  see above.
    */
   static boolean mustManageLegacyError(boolean forceBlockLevelUndoThrow)
   {
      return mustManageLegacyError(work.obtain(), forceBlockLevelUndoThrow);
   }
   
   /**
    * Check if the top-level block is ROUTINE-LEVEL UNDO, THROW or the current program is 
    * BLOCK-LEVEL UNDO, THROW.
    *
    * @param   wa
    *          The {@link WorkArea} instance.
    *          
    * @return  see above.
    */
   static boolean mustManageLegacyError(WorkArea wa)
   {
      return wa.pm._thisProcedure() != null && 
            ((wa.tm.isRootNestingLevel() && AppServerManager.isRemote() && wa.pm.isRoutineLevelUndoThrow()) || 
             (wa.tm.isTopLevelBlock() && wa.pm.isRoutineLevelUndoThrow())                                   || 
             wa.pm.isBlockLevelUndoThrow());
   }
   
   /**
    * Check whether the -catchStop startup parameter is set on 1.
    *
    * @param   wa
    *          The {@link WorkArea} instance.
    *          
    * @return  see above.
    */
   static boolean mustManageLegacyStop(WorkArea wa)
   {      
      return wa.catchStopParameter != 0;
   }
   
   /**
    * Check if we must throw a legacy compatible OO error.  This will happen if either 
    * {@link #mustManageLegacyError()} or anywhere on the stack the specified error is handled
    * by a CATCH block.
    * 
    * @param   errorClass
    *          The error class to be throw.
    * 
    * @return  See above.
    */
   static boolean mustThrowLegacyError(Class<? extends LegacyError> errorClass)
   {
      return mustThrowLegacyError(work.obtain(), errorClass);
   }
   
   /**
    * Check if we must throw a legacy compatible OO error.  This will happen if either 
    * {@link #mustManageLegacyError()} or anywhere on the stack the specified error is handled
    * by a CATCH block.
    * 
    * @param   errorClass
    *          The error class to be throw.
    * 
    * @return  See above.
    */
   static boolean mustThrowLegacyError(WorkArea wa, Class<? extends LegacyError> errorClass)
   {
      return mustManageLegacyError(wa) || hasLegacyError(wa, errorClass, 1);
   }
   
   /**
    * Check if any CATCH blocks defined at the specified enclosing block can manage this exception.
    * <p>
    * If none found, ignore this exception.  4GL doesn't seem to propagate the errors further than
    * then current block.
    * 
    * @param    type
    *           The error type to process.
    * @param    levels
    *           Flag indicating which block to use (0 for current, 1 for parent, etc).  Use -1 to search the
    *           entire stack.
    * 
    * @return   <code>true</code> if this exception can be processed by the current block.
    */
   static boolean hasLegacyError(Class<? extends LegacyError> type, int levels)
   {
      return hasLegacyError(work.obtain(), type, levels);
   }
   
   /**
    * Check if any CATCH blocks defined at the specified enclosing block can manage this stop exception.
    * <p>
    * If none found, ignore this exception.  4GL doesn't seem to propagate the errors further than
    * then current block.
    * 
    * @param    type
    *           The error type to process.
    * @param    levels
    *           Flag indicating which block to use (0 for current, 1 for parent, etc).  Use -1 to search the
    *           entire stack.
    * 
    * @return   <code>true</code> if this exception can be processed by the current block.
    */
   static boolean hasLegacyStop(Class<? extends Stop> type)
   {
      return hasLegacyStop(work.obtain(), type);
   }
   
   /**
    * Returns the type of return processing from the nearest top-level block.
    * The returned value is the value passed to {@link #returnWorker(WorkArea, Object, ReturnType)}.  
    * <p>
    * The value is valid from the time the converted code implementing the top-level
    * block is exited until after {@link Scopeable#scopeFinished()} is called.   
    * 
    * @return   Type of return processing value or <code>null</code> if the nearest
    *           top-level code is not finished by execution of 
    *           {@link #returnWorker(WorkArea, Object, ReturnType)}.
    */                         
   static ReturnType getReturnType()
   {
      return work.get().rtype;
   }
   
   /**
    * Get the function's return value.
    * 
    * @return   The latest {@link WorkArea#funcRet} value.
    */
   static Object getFunctionReturn()
   {
      Object ret = work.get().funcRet.peek();
      return ret == null || ret == NULL ? null : ret;
   }
   
   /**
    * Check the {@link WorkArea#funcRet} stack for the supplied condition.
    * 
    * @param    func
    *           The condition to check.
    *
    * @return   <code>true</code> if the condition applies to any of object in the return stack.
    */
   static boolean checkFunctionReturn(Function<Object, Boolean> func)
   {
      // only the top caller can have something to return 'in progress', everything else is still executing
      Object ret = work.get().funcRet.peek();
      if (ret == null)
      {
         return false;
      }

      if (ret.getClass().isArray())
      {
         int size = Array.getLength(ret);
         for (int j = 0; j < size; j++)
         {
            Object aret = Array.get(ret, j);
            if (func.apply(aret))
            {
               return true;
            }
         }
      }
      else
      {
         return func.apply(ret);
      }
      
      return false;
   }
   
   /**
    * Get an instance of {@link ProcedureHelper}, which has the context-local instance saved,
    * so API access can be done without a context-local query.
    * 
    * @return   See above.
    */
   static BlockManagerHelper getHelper()
   {
      return new BlockManagerHelper(work.get());
   }

   /**
    * Check if the <code>ErrorConditionException</code> was triggered in the caller and
    * throw a <code>LegacyErrorException</code>
    * 
    * @param exc
    *        The RuntimeException to propagate
    */
   private static void checkLegacyError(RuntimeException exc)
   {
      if (exc instanceof ErrorConditionException && ((ErrorConditionException) exc).isTriggeredInCaller())
      {
         object<? extends SysError> legacyError = SysError.newInstance(
                 exc.getMessage(),
                 ((ErrorConditionException) exc).getProgressErrorCode());
         throw new LegacyErrorException(legacyError);
      }
      throw exc;
   }

   /**
    * Execute the given top-level block with the given transaction level.
    *
    * @param    def
    *           The Java class associated with a legacy OE class, if this code is part of a legacy
    *           OE class; otherwise, <code>null</code>.
    * @param    referent
    *           The instance of the containing business logic class from which this is being
    *           called.  For external procedures, if this is non-null, then <code>block</code>
    *           can be an instance created using lambdas.  If <code>null</code>, then
    *           <code>block</code> MUST BE an anonymous inner class of the containing business
    *           logic instance so that instance can be calculated via reflection. For internal
    *           procedures and triggers, this is expected to be <code>null</code>.
    * @param    legacyName
    *           The legacy name associated with the function being invoked via a java-style call. 
    *           If is <code>null</code>, it will be resolved by 
    *           {@link ProcedureManager#resolveClosestMethod}.
    * @param    lvl
    *           The transaction level for the given block.
    * @param    btype
    *           The type of block represented by the given code.
    * @param    block
    *           The code to execute.
    */
   static void topLevelBlock(Class<?>        def,
                             Object          referent, 
                             String          legacyName, 
                             TransactionType lvl, 
                             BlockType       btype, 
                             Block           block)
   {
      long start = 0;
      if (statsFile != null)
      {
         start = System.currentTimeMillis();
      }
      
      if (def == null && referent != null && referent.getClass() == Class.class)
      {
         def = (Class<?>) referent;
      }
      
      // give the block a chance to handle any initialization which must happen BEFORE the TM
      // scope is pushed; doesn't repeat on retry
      block.pre();
      
      int     ttype = convertTransType(lvl, btype);
      boolean etype = (btype == BlockType.EXTERNAL_PROC);
      boolean ptype = (btype == BlockType.INTERNAL_PROC);
      
      WorkArea wa = work.obtain();
      
      // this checks if current block if current is either:
      // - session database trigger, so with trigger block type 
      // - schema database trigger, so with external procedure block type
      //   and database trigger referent
      boolean databaseTrigger = (etype                       &&
                                 referent != null            &&
                                 referent instanceof com.goldencode.p2j.persist.trigger.DatabaseTrigger) ||
                                btype == BlockType.DATABASETRIGGER;
      
      // external and internal procedures are allowed to be invoked outside of ControlFlowOps APIs
      // only from hand-written java code, but the conversion code emits only ControlFlowOps APIs
      // constructors are also invoked without ControlFlowOps APIs (emulated via internal proc).
      boolean javaCall = (etype || ptype);
      if (javaCall)
      {
          Boolean check = checkJavaCall(wa, def, referent, legacyName, block, false, etype, false);
          if (check == null)
          {
             return;
          }
          javaCall = check;
      }
      
      OutputParameterAssigner opa = wa.tm.deregisterOutputParameterAssigner();
      String calleeName = ""; // opa will need this back when performing exit checks 
      
      wa.tm.pushScope("methodScope",
                      ttype,
                      (PROP_ERROR | PROP_ENDKEY),
                      etype,
                      true,
                      false,
                      false,
                      databaseTrigger,
                      btype);
      
      // add a scope to our list of function return values and block types
      wa.topType.push(btype);
      
      try
      {
         methodScope:
         {
            // give the block a chance to initialize its state and don't
            // repeat that during retry
            block.init();
            
            wa.tm.blockSetup();
            
            do
            {
               try
               {
                  processBody(wa, block, null, null);
               }
               
               catch (LegacyErrorException lex)
               {
                  processLegacyException(wa, lex);
               }
               
               catch (LegacyStopException lex)
               {
                  processLegacyStopException(wa, lex);
               }
               
               catch (ErrorConditionException err)
               {
                  wa.tm.notifyCondition(err);
                  wa.tm.honorError(err);
                  wa.tm.rollback("methodScope");
                  wa.tm.triggerRetry("methodScope");
               }
               
               catch (StopConditionException err)
               {
                  wa.tm.notifyCondition(err);
                  wa.tm.rollback("methodScope");
                  throw err;
               }

               catch (InvalidParameterConditionException ipe)
               {
                  wa.tm.notifyCondition(Condition.ERROR);
                  wa.tm.rollback("methodScope");
                  throw new ErrorConditionException(ipe.getCause());
               }
               
               catch (EndConditionException end)
               {
                  wa.tm.notifyCondition(end);
                  wa.tm.rollback("methodScope");
                  break methodScope;
               }
               
               catch (RetryUnwindException rue)
               {
                  wa.tm.honorRetry(rue);
               }
               
               catch (StackUnwindException sue)
               {                  
                  // we have unwound to the exit point, break out (it doesn't
                  // matter whether we need to exit because of a LEAVE, NEXT
                  // or a RETURN, they all have the same result on a top-level
                  // block
                  break methodScope;
               }
               
               catch (Throwable thr)
               {
                  wa.tm.abnormalEnd(thr);
               }
            }
            while (wa.tm.needsRetry());
         }
      }
      catch (RuntimeException exc)
      {
         // cleaning up the OPA inside this catch only works because "normal"
         // control flow exceptions are caught and handled before they would
         // cross the top-level block boundary
         if (opa != null)
         {
            opa.abort();
         }
         checkLegacyError(exc);
      }
      finally
      {
         if (opa != null)
         {
            if (wa.rtype == BlockManager.ReturnType.ERROR)
            {
               opa.abort();
            }
            else
            {
               calleeName = wa.pm.getStackEntry(0);
            }
         }
         
         try
         {
            wa.tm.popScope();
            
         }
         catch (RuntimeException exc)
         {
            if (opa != null)
            {
               opa.abort();
            }
            
            throw exc;
         }
         finally
         {
            // cleanup our top level block state
            exitTopLevel(wa);
            wa.rtype = null;
            
            if (javaCall && (etype || ptype))
            {
               wa.pm.popCalleeInfo();
            }
         }

         if (statsFile != null)
         {
            recordExecutionStats(btype, block, start);
         }
      }
      
      // process assign-backs to database fields from output parameters, if any
      if (opa != null &&
          (btype == BlockType.EXTERNAL_PROC ||
           btype == BlockType.INTERNAL_PROC))
      {
         opa.processAssignments(calleeName, !(etype || ptype));
      }
   }
   
   /**
    * Register the abend code to be executed when the next top-level block needs to be invoked, as the 
    * argument assignment failed.
    * 
    * @param    abend
    *           The code to execute instead of the top-level block.
    */
   static void ignoreNextCall(Runnable abend)
   {
      WorkArea wa = work.get();
      if (wa.ignoreNextCall == null)
      {
         wa.ignoreNextCall = abend;
      }
   }
   
   /**
    * If the error referenced is an {@link AppError}, then also set the 
    * {@link ControlFlowOps#setReturnValue RETURN-VALUE}.
    * 
    * @param    wa
    *           Context local work area.  Must not be {@code null}.
    * @param    err
    *           The error being processed.
    * 
    * @return   <code>true</code> if this is referencing an {@link AppError} instance.
    */
   private static boolean setReturnValue(WorkArea wa, LegacyError err)
   {
      boolean fromRetVal = false;
      if (err instanceof AppError)
      {
         character retVal = ((AppError) err).getReturnValue();
         fromRetVal = true;
      
         if (retVal != null && !retVal.isUnknown() && !retVal.toStringMessage().isEmpty())
         {
            wa.cfops.setReturnValue(retVal);
         }
      }
      
      return fromRetVal;
   }
   
   /**
    * Break out of the block associated with the given label.  This will
    * unwind the stack until the proper block has been reached.  At that
    * point the block will be left using the Java "break" statement.
    *
    * @param    wa
    *           Context local work area.  Must not be {@code null}.
    * @param    label
    *           The name of the block to be left.
    *           
    * @throws   LeaveUnwindException 
    */
   private static void leave(WorkArea wa, String label)
   throws LeaveUnwindException
   {
      if (label != null)
      {
         wa.deferredLeave = label;
      }
      
      throw wa.leaveExc;
   }
   
   /**
    * Continue (iterate) the block associated with the given label.  This will
    * unwind the stack until the proper block has been reached.  At that
    * point the block will be iterated using the Java "continue" statement.
    *
    * @param    wa
    *           Context local work area.  Must not be {@code null}.
    * @param    label
    *           The name of the block to be iterated.
    * @throws   NextUnwindException 
    */
   private static void next(WorkArea wa, String label)
   throws NextUnwindException
   {
      if (label != null)
      {
         wa.deferredNext = label;
      }
      
      throw wa.nextExc;
   }
   
   /**
    * Check if we this call is a java-style call or is from {@link ControlFlowOps} APIs. If is
    * not from {@link ControlFlowOps}, then resolve {@link ProcedureManager.ProcedureHelper#pushCalleeInfo push 
    * the callee info}.
    * 
    * @param    wa
    *           Context local work area.  Must not be {@code null}.
    * @param    referent
    *           The instance of the containing business logic class from which this is being
    *           called.  For external procedures, if this is non-null, then <code>block</code>
    *           can be an instance created using lambdas.  If <code>null</code>, then
    *           <code>block</code> MUST BE an anonymous inner class of the containing business
    *           logic instance so that instance can be calculated via reflection. For internal
    *           procedures and functions, this is expected to be <code>null</code>.
    * @param    def
    *           The currently executing OE class or external program.
    * @param    legacyName
    *           The legacy name associated with the function/procedure being invoked via a 
    *           java-style call.  If is <code>null</code>, it will be resolved by 
    *           {@link ProcedureManager#resolveClosestMethod}.
    * @param    block
    *           The {@link Block} insance beeing executed.
    * @param    function
    *           Flag indicating if we are calling a function.
    * @param    externalProgram
    *           Flag indicating if we are calling an external program.
    * @param    persistentProc
    *           Flag indicating if the called external program is persistent.
    * 
    * @return   {@code true} if we are in a java-style call, <code>null</code> if we need to abend.
    */
   private static Boolean checkJavaCall(WorkArea wa,
                                        Class<?> def,
                                        Object   referent,
                                        String   legacyName,
                                        Block    block,
                                        boolean  function,
                                        boolean  externalProgram,
                                        boolean  persistentProc)
   {
      if (referent != null && referent instanceof Class)
      {
         // there is at least a case where ObjectOps.load is emitted in the Block.init method, 
         // and not in the Java method.  Anyway, we always emit the 'class referent', so we can
         // load it here
         wa.objHelper.load((Class) referent); 
      }
      
      boolean javaCall = !wa.pendingDynCall;
      wa.pendingDynCall = false;
      
      if (wa.ignoreNextCall != null)
      {
         try
         {
            wa.ignoreNextCall.run();
         }
         finally
         {
            wa.ignoreNextCall = null;
         }

         return null;
      }
      
      if (javaCall)
      {
         String iename;
         String pname;
         
         Class<?> defref = def;

         if (externalProgram)
         {
            // OO method call has a non-null referent
            if (referent == null)
            {
               referent = ProcedureManager.findRootEnclosingInstance(block);
            }
            else if (referent instanceof Class)
            {
               defref = (Class<?>) referent;
               referent = ObjectOps.getStaticInstance((Class<? extends _BaseObject_>) referent);
            }
            

            // safety first, this call won't work
            if (referent == null)
            {
               ErrorManager.handleStopException("Invalid referent in external procedure call.");
            }
            
            iename = ProcedureManager.EXTERNAL_PROGRAM;
            pname = SourceNameMapper.convertJavaProgSafe(referent.getClass().getName());
         }
         else
         {
            // OO method call has a non-null referent
            if (referent == null)
            {
               referent = wa.pm._thisProcedure();
            }
            else if (referent instanceof Class)
            {
               defref = (Class<?>) referent;
               referent = ObjectOps.getStaticInstance((Class<? extends _BaseObject_>) referent);
            }
            
            
            // we need to determine the legacy name of this call, so we can push it to the call
            // stack. fortunately, unlike the external program names, the internal entry names are 
            // reported as they are defined, not called
            if (legacyName == null)
            {
               iename = ProcedureManager.resolveClosestMethod(referent, function, externalProgram);
            }
            else
            {
               iename = legacyName;
            }
            pname = null;
         }
         
         if (defref == null)
         {
            if (referent.getClass() == Class.class)
            {
               defref = (Class<?>) referent;
            }
            else if (referent.getClass() == Object.class)
            {
               defref = ObjectOps.getStaticClass(referent);
            }
            else
            {
               defref = referent.getClass();
            }
         }
         wa.pm.pushCalleeInfo(defref, false, referent, referent, iename, pname, function, persistentProc);
         wa.pm.peekCalleeInfo().setLegacyName(iename);
      }
      
      return javaCall;
   }

   /**
    * Implements the body of all blocks or loops that are not related to the
    * <code>FOR</code> language statement. The main feature is to ensure that
    * any normal exit from the body will notify any <code>Commitable</code>
    * instances for validation purposes. A normal exit is a non-exception
    * return from {@link Block#body}, or certain exception cases related to
    * <code>LEAVE</code>, <code>NEXT</code>, <code>RETURN</code> or
    * <code>QUIT</code> when they are not associated with an <code>UNDO</code>.
    *
    * @param    wa
    *           Context local data or {@code null} if not available in the caller.
    * @param    block
    *           The block to execute.
    * @param    on
    *           List of user-defined ON phrases.  May be {@code null}.
    * @param    defOn
    *           List of implicit ON phrases for this block.  May be {@code null}.
    */
   private static void processBody(WorkArea wa, Block block, OnPhrase[] on, OnPhrase[] defOn)
   throws Throwable
   {
      Throwable reason = null;
      
      try
      {
         // check the interrupted status and throw the stop condition if needed
         wa.tm.honorStopCondition();
         
         block.body();
         
         // check the interrupted status and throw the stop condition if needed
         wa.tm.honorStopCondition();
      }
      catch (DeferredLegacyErrorException dlex)
      {
         LegacyErrorException lex = ErrorManager.getDeferredLegacyError();
         processLegacyError(wa, lex, on, defOn);
      }
      catch (LegacyErrorException lex)
      {
         processLegacyError(wa, lex, on, defOn);
      }
      catch (DeferredLegacyStopException dlex)
      {
         LegacyStopException lex = ErrorManager.getDeferredLegacyStop();
         processLegacyStop(wa, lex);
      }
      catch (LegacyStopException lex)
      {
         processLegacyStop(wa, lex);
      }
      catch (ConditionException e)
      {
         wa.tm.errHlp.addNumbersToConditionException(e);
         reason = e;
      }
      catch (Throwable thr)
      {
         reason = thr;
      }
      finally
      {
         if (wa.tm.isTransaction() && (reason == null || isNormal(wa, reason, on)))
         {
            executeStateManaged(wa, wa.tm::processValidate);
         }
         
         // the body executed at least once, so the fini() method must be called too
         if (block.hasFini())
         {
            // we cannot execute the FINALLY block here; it must be deferred to the end of iterate,
            // retry or block exit
            
            TransactionType lvl = block.finiMethod.getTransactionType();
            Block finiAsBlock = new Block((Body) block::fini);
            wa.tm.setupFinallyBlock(() -> doTerminationBlockWorker(wa, 
                                                                   lvl, 
                                                                   FINALLY_BLOCK_LABEL, 
                                                                   true,
                                                                   finiAsBlock));
         }
         
         if (reason != null)
         {
            throw reason;
         }
      }
   }
   
   /**
    * Implements the body of all <code>FOR</code> language statement blocks or
    * loops. The main feature is to ensure that any normal exit from the body
    * will notify any <code>Commitable</code> instances for validation
    * purposes. A normal exit is a non-exception return from {@link Block#body},
    * or certain exception cases related to <code>LEAVE</code>,
    * <code>NEXT</code>, <code>RETURN</code> or <code>QUIT</code> when they are
    * not associated with an <code>UNDO</code>.
    *
    * @param    wa
    *           Context local data or {@code null} if not available in the caller.
    * @param    block
    *           The block to execute.
    * @param    to                        
    *           The TO clause that defines the block condition. The block
    *           control variable is initialized before entering the block. 
    *           Before the block body is entered, the control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at that moment). if the termination condition is
    *           met, the block is never entered.
    * @param    expr      
    *           The WHILE clause that defines a block condition. This
    *           expression is evaluated before the block body is about to
    *           be entered.  The block body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    on
    *           List of user-defined ON phrases.  May be {@code null}.
    * @param    defOn
    *           List of implicit ON phrases for this block.  May be {@code null}.
    *
    * @return   <code>true</code> if the code should break out of the block
    *           on return (because the loop/block control expressions or
    *           incrementer forced an exit).
    */
   private static boolean processForBody(WorkArea   wa,
                                         Block      block,
                                         ToClause   to,
                                         LogicalOp  expr,
                                         OnPhrase[] on,
                                         OnPhrase[] defOn)
   throws Throwable
   {
      Throwable reason     = null;
      boolean   needsBreak = false;
      boolean   bodyRan    = false;
      
      try
      {
         wa.tm.honorStopCondition();
         // retrieve the record (only used in cases where there is a TO and/or WHILE)
         if (to != null || expr != null)
         {
            block.enter();
         }
         
         // evaluate any TO or WHILE condition and execute the block
         // body if both are null or when all non-null expressions
         // evaluate true; otherwise never execute the block body
         if (needsIterate(to, expr))
         {
            bodyRan = true;
            block.body();
            
            wa.tm.honorStopCondition();
         }
         else
         {
            needsBreak = true;
         }
      }
      catch (DeferredLegacyErrorException dlex)
      {
         LegacyErrorException lex = ErrorManager.getDeferredLegacyError();
         processLegacyError(wa, lex, on, defOn);
      }
      catch (LegacyErrorException lex)
      {
         processLegacyError(wa, lex, on, defOn);
      }
      catch (DeferredLegacyStopException dlex)
      {
         LegacyStopException lex = ErrorManager.getDeferredLegacyStop();
         processLegacyStop(wa, lex);
      }
      catch (LegacyStopException lex)
      {
         processLegacyStop(wa, lex);
      }
      
      catch (Throwable thr)
      {
         // for now, we are still processing the query as the first statement in the body
         // but this is known to cause some deviations in transaction state; one of the
         // problems that we fixup here is that the body doesn't really execute in this
         // case but without this code we would think that it had executed
         if (thr instanceof QueryOffEndException)
         {
            bodyRan = false;
         }
         
         reason = thr;
      }
      finally
      {
         if (reason == null || isNormal(wa, reason, on))
         {
            executeStateManaged(wa, wa.tm::processValidate);
         }
         
         // if the body executed then the fini() method must be called too
         if (bodyRan && block.hasFini())
         {
            // we cannot execute the FINALLY block here; it must be deferred to the end of iterate,
            // retry or block exit
            
            TransactionType lvl = block.finiMethod.getTransactionType();
            Block finiAsBlock = new Block((Body) block::fini);
            wa.tm.setupFinallyBlock(() -> doTerminationBlockWorker(wa, 
                                                                   lvl, 
                                                                   FINALLY_BLOCK_LABEL,
                                                                   true,
                                                                   finiAsBlock));
         }
         
         if (reason != null)
         {
            throw reason;
         }
      }
      
      return needsBreak;
   }
   
   /**
    * Detect if an exception represents a normal or abnormal condition.
    *
    * @param    wa
    *           Context local data or {@code null} if not available in the caller.
    * @param    thr
    *           The exception to analyze.
    * @param    on                  
    *           List of user-defined on phrases.
    *
    * @return   <code>true</code> if the exception is a normal control-flow
    *           condition.
    */
   private static boolean isNormal(WorkArea wa, Throwable thr, OnPhrase[] on)
   {
      // no exception means normal
      if (thr == null)
      {
         return true;
      }
      
      // LEAVE, NEXT and RETURN
      if (thr instanceof StackUnwindException)
      {         
         // check if an UNDO is NOT in effect
         if (!wa.tm.hadRollback())
         {
            return true;
         }
      }
      
      // QUIT
      if (thr instanceof QuitConditionException)
      {
         // if there are no user-defined ON phrases, then a QUIT is always
         // a commit instead of a rollback
         if (on == null)
         {
            return true;
         }
         
         // look for a user-defined ON QUIT phrase
         OnPhrase imple = matchCondition(on, null, Condition.QUIT);
         
         // if none, then QUIT will be a commit not a rollback
         if (imple == null)
         {
            return true;
         }
      }
      
      return false;
   }
   
   /**
    * Detect if there is a pending leave for the block named by the given
    * label. If so, this deferred leave flag will be cleared and 
    * <code>true</code> will be returned.  The caller is responsible for
    * ensuring that the leave request is fully granted as no further state
    * will be available for subsequent processing.
    *
    * @param    wa
    *           Local context.
    * @param    label
    *           The name of the block to be checked against the deferred
    *           leave block name.
    *
    * @return   <code>true</code> if there is a pending deferred leave and
    *           the name of the block to be left is the same as the given
    *           label. If the pending deferred block name is the "" (empty
    *           string), that is the equivalent of matching "any block" and
    *           so the first call to this method after that is set will cause
    *           a <code>true</code> to be returned.
    */
   private static boolean deferredLeaveWorker(WorkArea wa, String label)
   {
      if (wa == null)
         wa = work.obtain();
      
      if (wa.deferredLeave != null && label != null)
      {
         if (label.equals(wa.deferredLeave) || wa.deferredLeave.length() == 0)
         {
            // clear state
            wa.deferredLeave = null;
            
            return true;
         }
      }
      
      return false;
   }
   
   /**
    * Detect if there is a pending next for the block named by the given
    * label. If so, this deferred next flag will be cleared and 
    * <code>true</code> will be returned.  The caller is responsible for
    * ensuring that the next request is fully granted as no further state
    * will be available for subsequent processing.
    *
    * @param    wa
    *           Local context.
    * @param    label
    *           The name of the block to be checked against the deferred
    *           next block name.
    *
    * @return   <code>true</code> if there is a pending deferred next and
    *           the name of the block to be iterated is the same as the given
    *           label. If the pending deferred block name is the "" (empty
    *           string), that is the equivalent of matching "any block" and
    *           so the first call to this method after that is set will cause
    *           a <code>true</code> to be returned.
    */
   private static boolean deferredNextWorker(WorkArea wa, String label)
   {
      if (wa == null)
         wa = work.obtain();
      
      if (wa.deferredNext != null && label != null)
      {
         if (label.equals(wa.deferredNext) || wa.deferredNext.length() == 0)
         {
            // clear state
            wa.deferredNext = null;
            
            return true;
         }
      }
      
      return false;
   }
   
   /**
    * Return from the nearest enclosing top-level block. This will process
    * differently based on the type of the top-level block (internal/external
    * procedures, triggers or user-defined functions), the type of return
    * processing that is requested (see {@link ReturnType}) and the presence
    * or absence of a value to return.
    * <p>
    * The following behavior is provided:
    * <p>
    * <pre>
    * Codes   Meaning                
    * ------  -----------------------------------------------------
    * C       Invoke LogicalTerminal.consume()
    * E       Invoke TransactionManager.triggerErrorInCaller()
    * V       Invoke ControlFlowOps.setReturnValue(val)
    * N       Invoke ControlFlowOps.setReturnValue("")
    * F       Invoke setFuncReturn(val)
    * U       Invoke setFuncReturn(null) (set return value as unknown)
    * I       Invalid (compile error in Progress)
    *
    *  Return    Return    Internal  External  Trigger  Function
    *  Value      Type       Proc      Proc
    * --------  ---------  --------  --------  -------  --------
    * null      NORMAL     N         N         N        U
    * non-null  NORMAL     V         V         V        F
    * null      CONSUME    N         N         NC       U
    * non-null  CONSUME    V         V         VC       F
    * null      ERROR      NE        NE        I        U
    * non-null  ERROR      VE        VE        I        U
    * </pre>
    * <p>
    * In all cases, a {@link ReturnUnwindException} will be thrown and this
    * will cause the stack to unwind to the nearest enclosing top-level
    * block. That block will then handle the return in a block specific
    * manner.  For example, in a user-defined function, the given value or 
    * by default the <code>unknown value</code> will be returned to the
    * caller. Procedures and triggers have void return values.
    *
    * @param    val
    *           The value to return.
    * @param    rtype
    *           The type of return processing.
    */
   private static void returnWorker(BaseDataType val, ReturnType rtype)
   throws ReturnUnwindException
   {
      returnWorker(null, val, rtype);
   }
   
   /**
    * Return from the nearest enclosing top-level block. This will process
    * differently based on the type of the top-level block (internal/external
    * procedures, triggers or user-defined functions), the type of return
    * processing that is requested (see {@link ReturnType}) and the presence
    * or absence of a value to return.
    * <p>
    * The following behavior is provided:
    * <p>
    * <pre>
    * Codes   Meaning                
    * ------  -----------------------------------------------------
    * C       Invoke LogicalTerminal.consume()
    * E       Invoke TransactionManager.triggerErrorInCaller()
    * V       Invoke ControlFlowOps.setReturnValue(val)
    * N       Invoke ControlFlowOps.setReturnValue("")
    * F       Invoke setFuncReturn(val)
    * U       Invoke setFuncReturn(null) (set return value as unknown)
    * I       Invalid (compile error in Progress)
    *
    *  Return    Return    Internal  External  Trigger  Function
    *  Value      Type       Proc      Proc
    * --------  ---------  --------  --------  -------  --------
    * null      NORMAL     N         N         N        U
    * non-null  NORMAL     V         V         V        F
    * null      CONSUME    N         N         NC       U
    * non-null  CONSUME    V         V         VC       F
    * null      ERROR      NE        NE        I        U
    * non-null  ERROR      VE        VE        I        U
    * </pre>
    * <p>
    * In all cases, a {@link ReturnUnwindException} will be thrown and this
    * will cause the stack to unwind to the nearest enclosing top-level
    * block. That block will then handle the return in a block specific
    * manner.  For example, in a user-defined function, the given value or 
    * by default the <code>unknown value</code> will be returned to the
    * caller. Procedures and triggers have void return values.
    *
    * @param    wa
    *           Context local data or {@code null} if not available in caller.
    * @param    val
    *           The value to return. If the function doesn't return an extent value, the element
    *           zero will be returned.
    * @param    rtype
    *           The type of return processing.
    */
   private static void returnWorker(WorkArea wa, Object val, ReturnType rtype)
   throws ReturnUnwindException
   {
      if (wa == null)
         wa = work.obtain();
      
      BlockType nearest = topLevelType(wa);
      boolean   skipThrowLegacyError = false;
      
      // save the return processing type
      boolean store = (rtype == ReturnType.STORE);
      boolean retError = (rtype == ReturnType.ERROR);
      if (retError)
      {
         markReturnError(wa);
      }
      
      if (store)
      {
         rtype = ReturnType.NORMAL;
      }
      wa.rtype = rtype;
      
      if (nearest != null)
      {
         switch (nearest)
         {
            case DATABASETRIGGER:
            case TRIGGER:
               if (rtype == ReturnType.CONSUME)
               {
                  LogicalTerminal.consumeEvent();
               }
               else if (retError)
               {
                  String err = "RETURN ERROR is not allowed in a TRIGGER";
                  throw new IllegalArgumentException(err);
               }
               // fall through so that return-value is also set 
            case INTERNAL_PROC:
            case EXTERNAL_PROC:
               if (rtype == ReturnType.CONSUME && isPersistentTriggerTopLevel(wa))
               {
                  LogicalTerminal.consumeEvent();
               }

               if (val == null)
               {
                  wa.cfops.setReturnValue("");
               }
               else
               {
                  // the return value should always be of type character
                  // but this code just makes it safer
                  if (val instanceof unknown)
                  {
                     wa.cfops.setReturnValue(new character());
                  }
                  else if (val instanceof character)
                  {
                     character retVal = (character) val;
                     wa.cfops.setReturnValue(retVal);
                  }
               }
               break;
            case FUNCTION:
               // In the error case, even if a value is passed, it will be
               // forced to null; in the non-error cases if the value is null
               // then the result will be setting the return to unknown value
               // and if the value is not null, then that value will be set as
               // the return value.
               setFuncReturn(retError ? null : val, wa, nearest);
               // Quirk: 'return error' in ABL method *does* set error-status:error
               //        to true, while an ABL function leaves error-status as is.
               // Proof: xfer testcases rev 1274.
               CalleeInfo calinfo = (retError ? wa.pm.peekCalleeInfo() : null);
               // To avoid unnecessary peek calls, we only call isMethod() if needed further on.
               if (calinfo == null || !calinfo.isMethod())
               {
                  skipThrowLegacyError = true;
               }
               break;
            default:
               break;
         }
      }
      
      // functions don't raise error in the calling scope, methods do. 
      if (retError && !skipThrowLegacyError)
      {
         if (mustThrowLegacyError(wa, AppError.class))
         {
            try
            {
               // reset before the 'newInstance' call
               wa.rtype = null;
               
               object<? extends AppError> err = AppError.newInstance(ControlFlowOps.getReturnValue());
               err.ref.setFromReturn(true);
               LegacyErrorException lex = new LegacyErrorException(err, true);
               lex.setExplicit(true);
               wa.tm.triggerErrorInCaller(lex);
               throw lex;
            }
            finally
            {
               // set this again, as it gets changed by 'AppError.newInstance'
               wa.rtype = rtype;
            }
         }
         wa.tm.triggerErrorInCaller();
      }

      if (store)
      {
         // if 'storeReturnValue' is being called, then this is either the last RETURN in the block or is 
         // always followed by a Java 'return'.
         return;
      }
      else if (rtype == ReturnType.NORMAL && wa.tm.getBlockType() == BlockType.FUNCTION)
      {
         // otherwise, check if this return can skip the exception throw

         Object thisProc = wa.pm._thisProcedure();
         String clsName = null;
         if (thisProc instanceof _BaseObject_) 
         {
            clsName = thisProc.getClass().getName();
         }
         else if (thisProc.getClass() == Object.class)
         {
            // this case handles static OO method calls - for this, FWD uses a surrogate java.lang.Object 
            // instance to be used as THIS-PROCEDURE; THIS-PROCEDURE is how FWD internally identifies the
            // context of the current call (and for static calls there is no 'instance', thus the 
            // java.lang.Object surrogate).
            Class<? extends _BaseObject_> cls = ObjectOps.getStaticClass(thisProc);
            clsName = cls.getName();
         }
         
         // TODO: replace this test with cls.isAnnotation(LegacyResource.class) ?
         if (clsName != null && clsName.startsWith("com.goldencode.p2j.oo"))
         {
            // WARNING: the p2o.oo code is not refactored to use 'storeReturnValue' or Java return statements
            // instead, this code uses and expects for the returnNormal call to exit the block.
         }
         else
         {
            return;
         }
      }
      
      throw wa.retExc;
   }
   
   /**
    * Mark all blocks on the stack enclosed in this this top-level block (including it), as 
    * {@link BlockDefinition#wasReturnError}.
    * <p>
    * This is called only when a RETURN ERORR (from within a top-level block) is being called, and is meant to
    * mark all blocks on the stack, up to the nearest top-level block, that the exist is being done via a 
    * RETURN ERROR.
    * <p>
    * Do not call this method from other code.
    * 
    * @param    wa
    *           The context-local instance.
    */
   private static void markReturnError(WorkArea wa)
   {
      int i = 0;
      BlockDefinition blk = wa.tm.getBlock(i);
      while (blk != null && !blk.topLevel)
      {
         blk.wasReturnError = true;
         i = i + 1;
         blk = wa.tm.getBlock(i);
      }
      if (blk != null)
      {
         // this is the nearest top-level block
         blk.wasReturnError = true;
      }
   }
   
   /**
    * Execute the given function block with the given transaction level.
    *
    * @param    def
    *           The Java class associated with a legacy OE class, if this code is part of a legacy
    *           OE class; otherwise, <code>null</code>.
    * @param    referent
    *           The referent to which this method belongs.
    * @param    legacyName
    *           The legacy name associated with the function being invoked via a java-style call.
    *           If is <code>null</code>, it will be resolved by 
    *           {@link ProcedureManager#resolveClosestMethod}.
    * @param    level
    *           The transaction level for the given block.
    * @param    block
    *           The code to execute.
    * @param    retType
    *           The type of the return value which is used in the case the
    *           <code>unknown value</code> must be returned.
    * @param    extent
    *           For functions not returning an extent value, this is -1. Else, this extent size,
    *           which is 0 for dynamic-extent and &gt;0 for fixed extent.
    *
    * @return   The return value from the block (or its nested blocks) which
    *           is the <code>unknown value</code> by default or on error.
    */
   @SuppressWarnings("unchecked")
   private static <T extends BaseDataType> Object functionBlock(Class<?>        def,
                                                                Object          referent,
                                                                String          legacyName,
                                                                TransactionType level,
                                                                Block           block,
                                                                Class<T>        retType,
                                                                int             extent)
   {
      WorkArea wa = work.obtain(); 
      Boolean javaCall = checkJavaCall(wa, def, referent, legacyName, block, true, false, false);
      if (javaCall == null)
      {
         // terminate the call
         return BaseDataType.generateUnknown(retType);
      }
      
      if (object.class == retType || (retType.isArray() && object.class == retType.getComponentType()))
      {
         wa.objHelper.registerPendingScopeable();
      }
      
      long start = 0;
      
      if (statsFile != null)
      {
         start = System.currentTimeMillis();
      }
      
      // give the block a chance to handle any initialization which must happen BEFORE the TM
      // scope is pushed; doesn't repeat on retry
      block.pre();
      
      OutputParameterAssigner opa = wa.tm.deregisterOutputParameterAssigner();
      String calleeName = ""; // opa will need this back when performing exit checks 
      boolean wasDynamicCall = false;
      
      Object retVal = null;
      
      int ttype = convertTransType(level, BlockType.FUNCTION);
      wa.tm.pushScope("methodScope",
                      ttype,
                      (PROP_ERROR | PROP_ENDKEY),
                      false,
                      true,
                      false,
                      false,
                      BlockType.FUNCTION);
      
      // add a scope to our list of function return values and block types
      wa.funcRet.push(NULL);
      wa.topType.push(BlockType.FUNCTION);
      
      try
      {
         methodScope:
         {
            // give the block a chance to initialize its state and don't repeat that during retry
            block.init();
            
            wa.tm.blockSetup();
            
            do
            {
               try
               {
                  processBody(wa, block, null, null);
               }
               
               catch (LegacyErrorException lex)
               {
                  processLegacyException(wa, lex);
               }
               
               catch (LegacyStopException lex)
               {
                  processLegacyStopException(wa, lex);
               }
               
               catch (ErrorConditionException err)
               {
                  // we deliberately do not test honorError() here since
                  // functions in Progress do not implement the "trigger
                  // error in caller" behavior on a return error
                  wa.tm.notifyCondition(err);
                  wa.tm.rollback("methodScope", err);
                  wa.tm.triggerRetry("methodScope");
               }
               
               catch (StopConditionException err)
               {
                  wa.tm.notifyCondition(err);
                  wa.tm.rollback("methodScope", err);
                  throw err;
               }
               
               catch (EndConditionException end)
               {
                  wa.tm.notifyCondition(end);
                  wa.tm.rollback("methodScope", end);
                  break methodScope;
               }
               
               catch (RetryUnwindException rue)
               {
                  wa.tm.honorRetry(rue);
               }
               
               catch (StackUnwindException sue)
               {                  
                  // we have unwound to the exit point, break out (it doesn't
                  // matter whether we need to exit because of a LEAVE, NEXT or
                  // a RETURN, they all have the same result on a function block
                  break methodScope;
               }
               
               catch (Throwable thr)
               {
                  wa.tm.abnormalEnd(thr);
               }
            }
            while (wa.tm.needsRetry());
         }
      }
      catch (RuntimeException exc)
      {
         // cleaning up the OPA inside this catch only works because "normal"
         // control flow exceptions are caught and handled before they would
         // cross the top-level block boundary
         if (opa != null)
         {
            opa.abort();
         }
         checkLegacyError(exc);
      }
      finally
      {
         if (opa != null)
         {
            if (wa.rtype == BlockManager.ReturnType.ERROR)
            {
               opa.abort();
            }
            else
            {
               calleeName = wa.pm.getStackEntry(0);
            }
         }
         
         try
         {
            wa.tm.popScope();
         }
         catch (RuntimeException exc)
         {
            if (opa != null)
            {
               opa.abort();
            }
            
            throw exc;
         }
         finally
         {
            // cleanup return value stack and obtain the current value
            retVal = wa.funcRet.pop();
            if (retVal == NULL)
            {
               retVal = null;
            }
            
            // cleanup our top level block state
            exitTopLevel(wa);

            wa.rtype = null;

            if (javaCall)
            {
               wasDynamicCall = wa.pm.peekCalleeInfo().isDynamicCall();
               wa.pm.popCalleeInfo();
            }
         }

         if (statsFile != null)
         {
            recordExecutionStats(BlockType.FUNCTION, block, start);
         }
      }
      
      // process assign-backs to database fields from output parameters, if any
      if (opa != null)
      {
         opa.processAssignments(calleeName, true);
      }
      
      // assume no-extent
      int size = 1;
      if (extent >= 0)
      {
         int retValLength = retVal == null 
                              ? extent 
                              : retVal.getClass().isArray() ? Array.getLength(retVal) : 1;
         if (extent > 0 && retVal != null && retValLength != extent)
         {
            // TODO: if fixed extent, it must be of the same size
         }

         size = retVal == null ? extent : retValLength;

         T[] ret = (T[]) Array.newInstance(retType, size);
         for (int i = 0; i < size; i++)
         {
            if (retVal == null)
            {
               ret[i] = (T) BaseDataType.generateUnknown(retType);
            }
            else
            {
               try
               {
                  // In order to return the expected type, look for the "conversion" constructor
                  // of the type expected to return having as argument an object of the type
                  // we received in return statement. Then use it to create a new instance.
                  T t = null;
                  BaseDataType val = (BaseDataType) Array.get(retVal, i);
                  
                  if (retType == memptr.class && val instanceof memptr)
                  {
                     t = (T) val;
                  }
                  else
                  {
                     t = (T) BaseDataTypeFactory.instantiate(retType);
                     t.assign((BaseDataType) val);
                  }
                  ret[i] = t;
               }
               catch (ConditionException ce)
               {
                  // some 4GL validation/conversion error occurred
                  // propagate, will be handled elsewhere
                  throw ce;
               }
               catch (Exception ex)
               {
                  Throwable ex2 = ex;
                  while (ex2 != null && !(ex2 instanceof ConditionException))
                  {
                     ex2 = ex2.getCause();
                  }
                  
                  if (ex2 == null)
                  {
                     // wrap in a RunnableException and rethrow
                     throw new RuntimeException(ex);
                  }
                  else
                  {
                     // ex2 is instance of ConditionException because of a 4GL validation/conversion
                     // error has occurred: propagate, will be handled elsewhere
                     throw (ConditionException) ex2;
                  }
               }
            }
         }

         return ret;
      }
      else
      {
         if (retVal == null)
         {
            return BaseDataType.generateUnknown(retType);
         }
         else
         {
            try
            {
               BaseDataType ret;
               
               if (memptr.class == retType && retVal instanceof memptr)
               {
                  ret = (memptr) retVal;
               }
               else if ((retType == BaseDataType.class ||
                        BaseDataType.isProxy((BaseDataType) retVal) ||
                        ((javaCall && wasDynamicCall) || 
                         (!javaCall && wa.pm.peekCalleeInfo().isDynamicCall()))) &&
                        ((BaseDataType) retVal).val().getType().getCls() != retType)
               {
                  // any dynamic function should provide a proxy for the return value instead:
                  // - in 4GL, returning a value which comes from a dynamic-function invocation
                  // can bypass the return data type
                  // - in Java, we should ensure that the returned value ALWAYS matches the defined return
                  // data type; that is why we encapsulate this value using a proxy
                  ret = BaseDataType.createProxy(((BaseDataType) retVal).val(), 
                        (Class<? extends BaseDataType>) retType);
               }
               else
               {
                  retVal = ((BaseDataType) retVal).val();
                  if (integer.class == retType && retVal instanceof int64)
                  {
                     ret = new integer()
                     {
                        @Override
                        boolean isAssignDirect()
                        {
                           return true;
                        }
                     };
                  }
                  else if (retType == object.class && ((object) retVal)._isValid())
                  {
                     // create a ObjectVar and register it with the current block - the return reference can
                     // end up only 'on the stack' as a return value, if the reference will never be assigned;
                     // more, ObjectOps.instanceReturned will prohibit the reference to be deleted (as it 
                     // waits to 'maybe be assigned to something'). 
                     
                     wa.objHelper.registerScopeable();
                     
                     ret = new ObjectVar<>(((object) retVal).type());
                     wa.objHelper.registerObject((ObjectVar) ret);
                  }
                  else
                  {
                     ret = BaseDataTypeFactory.instantiate(retType);
                  }
                  
                  ret.assign((BaseDataType) retVal);

                  // preserve case sensitivity of the returned value
                  if (retVal instanceof Text)
                  {
                     ((Text) ret).setCaseSensitive(((Text) retVal).isCaseSensitive());
                  }
               }
               
               return ret;
            }
            catch (ConditionException ce)
            {
               // some 4GL validation/conversion error occurred
               // propagate, will be handled elsewhere
               throw ce;
            }
            catch (Exception ex)
            {
               Throwable ex2 = ex;
               while (ex2 != null && !(ex2 instanceof ConditionException))
               {
                  ex2 = ex2.getCause();
               }
               
               if (ex2 == null)
               {
                  // wrap in a RunnableException and rethrow
                  throw new RuntimeException(ex);
               }
               else
               {
                  // ex2 is instance of ConditionException because of a 4GL validation/conversion
                  // error has occurred: propagate, will be handled elsewhere
                  throw (ConditionException) ex2;
               }
            }
         }
      }
   }
   
   /**
    * Execute the given editing block for the given frame and widget list
    * with <code>UPDATE</code> semanics. All looping, sub-transaction
    * properties and block properties will be honored.  The exit from the
    * editing block will be based on the given <code>GO-ON</code> event list.
    *
    * @param    frame
    *           The frame for which the editing block is associated.
    * @param    widgets
    *           The widgets in the given frame that are to be enabled for
    *           editing.   
    * @param    goOn       
    *           The exit conditions for this loop or <code>null</code> if
    *           there are no explicit exit conditions.
    * @param    enclosing
    *           The list of enclosing blocks of which this class is unaware.
    *           Any LEAVE or NEXT that references one of those enclosing
    *           blocks must not unwind the stack further using an exception,
    *           but rather it must return and let the caller check to see if
    *           a deferred LEAVE or NEXT must be honored.
    * @param    label
    *           The label of the block for use in control flow statements
    *           such as <code>LEAVE</code> or <code>NEXT</code>.
    * @param    block
    *           The code for the editing block body.
    * @param    etype
    *           Editing block semantics (<code>CommonFrame.PROMPT-FOR</code>,
    *           <code>CommonFrame.SET</code> or
    *           <code>CommonFrame.UPDATE</code>).
    */
   private static void editingBlock(CommonFrame    frame,
                                    FrameElement[] widgets,
                                    EventList      goOn,
                                    String[]       enclosing,
                                    String         label,
                                    Block          block,
                                    int            etype)
   {
      boolean noWidgets = true;
      for (FrameElement el : widgets)
      {
         if (el != null)
         {
            noWidgets = false;
            break;
         }
      }
      
      if (noWidgets)
      {
         // the editing loop is a no-op if no widget was specified (as i.e. all WHEN clauses were
         // false)
         return;
      }
      
      if (UnnamedStreams.input() != null)
      {
         switch (etype) 
         {
            case CommonFrame.PROMPT_FOR:
            {
               frame.promptFor(widgets, goOn);
               break;
            }
            case CommonFrame.SET:
            {
               frame.set(widgets, goOn);
               break;
            }
            case CommonFrame.UPDATE:
            {
               frame.update(widgets, goOn);
               break;
            }
         }
         
         return;   
      }
      
      
      BufferManager.registerPendingScopeable(null);
      // give the block a chance to handle any initialization which must happen BEFORE the TM
      // scope is pushed; doesn't repeat on retry
      block.pre();
      
      WorkArea wa = work.obtain();
      
      wa.tm.pushScope(label,
                      convertTransType(TransactionType.SUB, BlockType.EDITING),
                      PROP_ERROR,
                      false,
                      false,
                      true,
                      true,
                      BlockType.EDITING);
      
      try
      {
         // give the block a chance to initialize its state and don't
         // repeat that during retry
         block.init();
         
         // prepare the frame and the client for the editing block, this
         // must only occur once (outside of the loop body and not being
         // re-executed on retry)
         if (goOn == null)
         {
            frame.startEditingMode(widgets, etype);
         }
         else
         {
            frame.startEditingMode(widgets, etype, goOn);
         }
         
         boolean hadNext = false;
         
         editing:
         do
         {
            wa.tm.blockSetup();
            
            do
            {
               // reset at the beginning of each iteration
               hadNext = false;
               
               try
               {
                  processBody(wa, block, null, null);
               }
               
               catch (ErrorConditionException err)
               {
                  wa.tm.notifyCondition(err);
                  
                  // EDITING blocks propagate ERROR conditions to the
                  // containing block, in 2 cases:
                  // 1. PROMPT-FOR or SET semantics
                  // 2. No matter the type of editing block (even if it is
                  //    an UPDATE), if the condition was raised as a result
                  //    of the END-ERROR key AND the editing block's "local"
                  //    interaction number < 2
                  if (etype != CommonFrame.UPDATE ||
                      (err.isEndError() && (wa.tm.getInteractions() < 2)))
                  {
                     throw err;
                  }

                  // If the EDITING semantic is for an UPDATE type block AND
                  // the ERROR condition was NOT raised as a result of an
                  // END-ERROR key press if "local" interaction number < 2,
                  // then AND ONLY THEN we will act as if there was an UNDO,
                  // RETRY of the EDITING block.
                  wa.tm.honorError(err);
                  wa.tm.rollback(label, err);
                  wa.tm.triggerRetry(null);
               }
               
               catch (RetryUnwindException rue)
               {
                  wa.tm.honorRetry(rue);
               }
               
               catch (LeaveUnwindException lue)
               {
                  if (testLeave(wa, enclosing, label) == Disposition.BREAK)
                  {
                     boolean res = LogicalTerminal.getClient().validateDisplayValue();
                     if (!res)
                     {
                        continue editing;
                     }
                     
                     // the LEAVE targeted this block or an enclosing non-managed block
                     break editing;
                  }
                  
                  // the LEAVE must be referencing an enclosing block which IS
                  // known to the block manager OR to one of the other
                  // enclosing managed blocks, so keep unwinding the stack
                  throw lue;
               }
               
               catch (NextUnwindException nue)
               {
                  switch (testNext(wa, enclosing, label))
                  {
                     case BREAK:
                        // a NEXT targeted at a directly enclosing block that is not managed
                        break editing;
                        
                     case CONTINUE:
                        // a NEXT targeted at this block
                        hadNext = true;
                        continue editing;
                        
                     default:
                        // the NEXT must be referencing an enclosing block
                        // which IS known to the block manager OR to one of
                        // the other enclosing managed blocks, so keep
                        // unwinding the stack
                        throw nue;
                  }
               }
               
               catch (ReturnUnwindException ret)
               {
                  // this isn't a top level block, keep unwinding without
                  // treating this as an abend
                  throw ret;
               }
               
               catch (Throwable thr)
               {
                  wa.tm.abnormalEnd(thr);
               }
            }
            while (wa.tm.needsRetry());
            
            if (wa.tm.isBreakPending())
            {
               break editing;
            }
         }
         while (frame.continueEditing(widgets, hadNext));
      }
      
      finally
      {
         wa.tm.popScope();
      }
   }
   
   /**
    * Execute a simple DO block (not a loop) with the given configuration and no default properties.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    enclosing
    *           The list of non-managed block names that enclose the current block.
    * @param    label
    *           The block name of the current block.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   private static void doBlockWorker(TransactionType lvl,
                                     String[]        enclosing,
                                     String          label,
                                     OnPhrase[]      on,
                                     Block           block)
   {
      // give the block a chance to handle any initialization which must happen BEFORE the TM
      // scope is pushed; doesn't repeat on retry
      block.pre();
      
      BlockType blockType = BlockType.DO;
      
      int ttype = convertTransType(lvl, blockType);
      
      OnPhrase[] defOn = null;
      
      if (lvl == TransactionType.FULL)
      {
         defOn = new OnPhrase[1];
         defOn[0] = new OnPhrase(Condition.ERROR, Action.RETRY, label);
      }
      
      int props = decodeConditions(defOn, on);
      
      WorkArea wa = work.obtain();
      
      wa.tm.pushScope(label, ttype, props, false, false, false, false, blockType);
      
      try
      {
         try
         {
            // each constructed query during block initialization will be
            // collected
            wa.tm.startOffEndRegistration();
            
            // give the block a chance to initialize its state and don't
            // repeat that during retry
            block.init();
         }
         finally
         {
            wa.tm.stopOffEndRegistration();

            // after all queries were created and registered, they must be
            // reset so the buffers reference no record.
            Set<QueryOffEndListener> listeners = wa.tm.getOffEndListeners(true);
            
            for (QueryOffEndListener qoel : listeners)
            {
               qoel.reset();
            }
         }
         
         wa.tm.blockSetup();
         
         blockLabel:
         do
         {
            try
            {
               processBody(wa, block, on, defOn);
            }
            
            catch (LegacyErrorException lex)
            {
               processLegacyException(wa, lex);
            }
            
            catch (LegacyStopException lex)
            {
               processLegacyStopException(wa, lex);
            }
            
            catch (ConditionException ce)
            {
               wa.tm.notifyCondition(ce);
               
               switch (processCondition(wa, on, defOn, ce, enclosing, label))
               {
                  // note that this is not an iterating block so a leave or
                  // next targeted at this block must always act the same
                  case BREAK:
                  case CONTINUE:
                     break blockLabel;
                  default:
                     break;
               }
            }
            
            catch (RetryUnwindException rue)
            {
               wa.tm.honorRetry(rue);
            }
            
            catch (LeaveUnwindException lue)
            {
               if (testLeave(wa, enclosing, label) == Disposition.BREAK)
               {
                  // the LEAVE targeted this block or an enclosing
                  // non-managed block
                  break blockLabel;
               }
               
               // the LEAVE must be referencing an enclosing block which IS
               // known to the block manager OR to one of the other enclosing
               // managed blocks, so keep unwinding the stack
               throw lue;
            }
            
            catch (NextUnwindException nue)
            {
               if (testNext(wa, enclosing, label) == Disposition.BREAK)
               {
                  // the NEXT can't be targeted at this block BUT it can be
                  // targeted at an enclosing non-managed block
                  break blockLabel;
               }
               
               // the NEXT must be referencing an enclosing block which IS
               // known to the block manager OR to one of the other enclosing
               // managed blocks, so keep unwinding the stack
               throw nue;
            }
            
            catch (ReturnUnwindException rue)
            {
               // RETURN can't be targeted at a DO block so keep unwinding
               throw rue;
            }
            
            catch (Throwable thr)
            {
               wa.tm.abnormalEnd(thr);
            }
         }
         while (wa.tm.needsRetry());
      }
      
      finally
      {
         wa.tm.popScope();
      }
   }
   
   /**
    * Execute a a termination block like CATCH and FINALLY, emulating {@link #doBlockWorker}. 
    *
    * @param    wa
    *           The {@link WorkArea} instance.
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    label
    *           The block name of the current block.
    * @param    finBlock
    *           Flag identifying a FINALLY block when <code>true</code> and a CATCH block otherwise.
    * @param    block
    *           The code to execute.
    */
   private static void doTerminationBlockWorker(WorkArea        wa,
                                                TransactionType lvl,
                                                String          label,
                                                boolean         finBlock,
                                                Block           block)
   {
      String[] enclosing = null;
      OnPhrase[] on = null;
      
      // give the block a chance to handle any initialization which must happen BEFORE the TM scope is pushed; 
      // doesn't repeat on retry
      block.pre();
      
      BlockType blockType = finBlock ? BlockType.FINALLY : BlockType.DO;
      
      int ttype = convertTransType(lvl, blockType);
      
      OnPhrase[] defOn = null;
      
      if (lvl == TransactionType.FULL)
      {
         defOn = new OnPhrase[1];
         defOn[0] = new OnPhrase(Condition.ERROR, Action.RETRY, label);
      }
      
      int props = decodeConditions(defOn, on);
      
      if (wa == null)
      {
         wa = work.obtain();
      }
      
      wa.tm.pushScope(label, ttype, props, false, false, false, false, blockType);
      
      try
      {
         block.init();
         
         wa.tm.blockSetup();
         
         // a CATCH or FINALLY block can't be retried
         blockLabel:
         {
            try
            {
               processBody(wa, block, on, defOn);
            }
            
            catch (LegacyErrorException lex)
            {
               processLegacyException(wa, lex);
            }
            
            catch (LegacyStopException lex)
            {
               processLegacyStopException(wa, lex);
            }
            
            catch (ConditionException ce)
            {
               wa.tm.notifyCondition(ce);
               
               switch (processCondition(wa, on, defOn, ce, enclosing, label))
               {
                  // note that this is not an iterating block so a leave or
                  // next targeted at this block must always act the same
                  case BREAK:
                  case CONTINUE:
                     break blockLabel;
                  default:
                     break;
               }
            }
            
            catch (RetryUnwindException rue)
            {
               wa.tm.honorRetry(rue);
            }
            
            catch (LeaveUnwindException lue)
            {
               if (testLeave(wa, enclosing, label) == Disposition.BREAK)
               {
                  // the LEAVE targeted this block or an enclosing
                  // non-managed block
                  break blockLabel;
               }
               
               // the LEAVE must be referencing an enclosing block which IS
               // known to the block manager OR to one of the other enclosing
               // managed blocks, so keep unwinding the stack
               throw lue;
            }
            
            catch (NextUnwindException nue)
            {
               if (testNext(wa, enclosing, label) == Disposition.BREAK)
               {
                  // the NEXT can't be targeted at this block BUT it can be
                  // targeted at an enclosing non-managed block
                  break blockLabel;
               }
               
               // the NEXT must be referencing an enclosing block which IS
               // known to the block manager OR to one of the other enclosing
               // managed blocks, so keep unwinding the stack
               throw nue;
            }
            
            catch (ReturnUnwindException rue)
            {
               // RETURN can't be targeted at a DO block so keep unwinding
               throw rue;
            }
            
            catch (Throwable thr)
            {
               wa.tm.abnormalEnd(thr);
            }
         }
      }
      
      finally
      {
         wa.tm.popScope();
      }
   }
   
   /**
    * Execute a DO WHILE expression, DO TO var = val1 to val2 by val3 or DO
    * TO WHILE expression loop with the given configuration and no default
    * properties.  At least one of the to clause or while expression must be
    * passed and it is valid to have both passed in which case both of the
    * conditions are tested with a logical AND.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends. If this is <code>null</code>,
    *           then a WHILE clause MUST be present to provide the condition
    *           for maintaining the loop.
    * @param    expr
    *           The WHILE clause that defines a loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>. If this is
    *           <code>null</code>, then a TO clause MUST be present to
    *           provide the condition for maintaining the loop.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   private static void doLoopWorker(TransactionType lvl,
                                    String[]        enclosing,
                                    String          label,
                                    ToClause        to,
                                    LogicalOp       expr,
                                    OnPhrase[]      on,
                                    Block           block)
   {
      BlockType btype = null;
      boolean   next  = false;
      
      if (to == null)
      {
         if (expr == null)
         {
            throw new IllegalStateException("DO loop MUST have a TO or WHILE clause.");
         }
         else
         {
            btype = BlockType.DO_WHILE;
         }
      }
      else
      {
         btype = (expr == null) ? BlockType.DO_TO : BlockType.DO_TO_WHILE;
         next  = true;
      }
      
      OnPhrase[] defOn = null;
      
      if (lvl == TransactionType.FULL)
      {
         defOn = new OnPhrase[1];
         defOn[0] = new OnPhrase(Condition.ERROR, Action.RETRY, label);
      }
      
      // process the loop
      coreLoop(btype, next, lvl, enclosing, label, to, expr, on, defOn, block);
   }
   
   /**
    * Execute a REPEAT, REPEAT WHILE expression, REPEAT TO var = val1 to val2
    * by val3 or REPEAT TO WHILE expression loop with the given configuration
    * and with default properties.  If neither the to clause or while
    * expression is specified, this is an infinite loop. If both are specified
    * then both of the conditions are tested with a logical AND. By default,
    * the ON ENDKEY UNDO, LEAVE and ON ERROR UNDO, RETRY properties are
    * supported.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends. If this is <code>null</code>,
    *           then a WHILE clause MUST be present to provide the condition
    *           for maintaining the loop.
    * @param    expr      
    *           The WHILE clause that defines a loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>. If this is
    *           <code>null</code>, then a TO clause MUST be present to
    *           provide the condition for maintaining the loop.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   private static void repeatWorker(TransactionType lvl,
                                    String[]        enclosing,
                                    String          label,
                                    ToClause        to,
                                    LogicalOp       expr,
                                    OnPhrase[]      on,
                                    Block           block)
   {
      BlockType btype = null;
      boolean next = false;
      
      if (to == null)
      {
         btype = (expr == null) ? BlockType.REPEAT : BlockType.REPEAT_WHILE;
      }
      else
      {
         btype = (expr == null) ? BlockType.REPEAT_TO : BlockType.REPEAT_TO_WHILE;
         next  = true;
      }
      
      OnPhrase[] defOn = new OnPhrase[2];
      defOn[0] = new OnPhrase(Condition.ENDKEY, Action.LEAVE, label);
      defOn[1] = new OnPhrase(Condition.ERROR, Action.RETRY, label);
      
      // process the loop
      coreLoop(btype, next, lvl, enclosing, label, to, expr, on, defOn, block);
   }
      
   /**                   
    * Execute a DO or REPEAT loop with all possible loop constructs, the
    * given configuration and with default properties.
    *
    * @param    btype
    *           Current block type.
    * @param    next
    *           <code>true</code> if on infinite loop protection a retry
    *           should be converted to a NEXT, <code>false</code> to convert
    *           to a LEAVE.
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends. If this is <code>null</code>,
    *           then a WHILE clause MUST be present to provide the condition
    *           for maintaining the loop.
    * @param    expr      
    *           The WHILE clause that defines a loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>. If this is
    *           <code>null</code>, then a TO clause MUST be present to
    *           provide the condition for maintaining the loop.
    * @param    on
    *           List of user-defined on phrases.
    * @param    defOn
    *           List of default properties for the block. Use
    *           <code>null</code> to indicate no default properties for the
    *           block.
    * @param    block
    *           The code to execute.
    */
   private static void coreLoop(BlockType       btype,
                                boolean         next,
                                TransactionType lvl,
                                String[]        enclosing,
                                String          label,
                                ToClause        to,
                                LogicalOp       expr,
                                OnPhrase[]      on,
                                OnPhrase[]      defOn,
                                Block           block)
   {
      // give the block a chance to handle any initialization which must happen BEFORE the TM
      // scope is pushed; doesn't repeat on retry
      block.pre();
      
      int ttype = convertTransType(lvl, btype);
      int props = decodeConditions(defOn, on);
      
      WorkArea wa = work.obtain();
      
      wa.tm.pushScope(label, ttype, props, false, false, true, next, btype);
      
      try
      {
         try
         {
            // each constructed query during block initialization will be
            // collected
            wa.tm.startOffEndRegistration();
            
            // give the block a chance to initialize its state and don't
            // repeat that during iteration or retry
            block.init();
         }
         finally
         {
            wa.tm.stopOffEndRegistration();

            // after all queries were created and registered, they must be
            // reset so the buffers reference no record.
            Set<QueryOffEndListener> listeners = wa.tm.getOffEndListeners(true);
            
            if (!listeners.isEmpty())
            {
               for (QueryOffEndListener qoel : listeners)
               {
                  qoel.reset();
               }
            }
         }
         
         loop:
         while (needsIterate(to, expr))
         {
            wa.tm.blockSetup();
         
            do
            {
               try
               {
                  processBody(wa, block, on, defOn);
               }
               
               catch (LegacyErrorException lex)
               {
                  processLegacyException(wa, lex);
               }
               
               catch (LegacyStopException lex)
               {
                  processLegacyStopException(wa, lex);
               }
               
               catch (ConditionException ce)
               {
                  wa.tm.notifyCondition(ce);
                  
                  switch (processCondition(wa, on, defOn, ce, enclosing, label))
                  {
                     case BREAK:
                        break loop;
                     case CONTINUE:
                        continue loop;
                     default:
                        break;
                  }
               }
               
               catch (RetryUnwindException rue)
               {
                  wa.tm.honorRetry(rue);
               }
               
               catch (LeaveUnwindException lue)
               {
                  if (testLeave(wa, enclosing, label) == Disposition.BREAK)
                  {
                     // the LEAVE targeted this block or an enclosing
                     // non-managed block
                     break loop;
                  }
                  
                  // the LEAVE must be referencing an enclosing block which IS
                  // known to the block manager OR to one of the other
                  // enclosing managed blocks, so keep unwinding the stack
                  throw lue;
               }
               
               catch (NextUnwindException nue)
               {
                  switch (testNext(wa, enclosing, label))
                  {
                     case BREAK:
                        // the NEXT is targeted at an enclosing non-managed block
                        break loop;
                        
                     case CONTINUE:
                        // the NEXT is targeted at the current loop
                        continue loop;
                        
                     default:
                        break;
                  }
                  
                  // the NEXT must be referencing an enclosing block which IS
                  // known to the block manager OR to one of the other
                  // enclosing managed blocks, so keep unwinding the stack
                  throw nue;
               }
               
               catch (ReturnUnwindException rue)
               {
                  // RETURN can't be targeted at a DO loop so keep unwinding
                  throw rue;
               }
               
               catch (Throwable thr)
               {
                  wa.tm.abnormalEnd(thr);
               }
            }
            while (wa.tm.needsRetry());
            
            if (wa.tm.isBreakPending())
            {
               break loop;
            }
         }
      }
      
      finally
      {
         wa.tm.popScope();
      }
   }
   
   /**
    * Execute a FOR FIRST/LAST WHILE block, FOR FIRST/LAST TO block
    * or FOR FIRST/LAST TO WHILE block with the given configuration and
    * with default properties.  Any TO or WHILE clause is treated as an
    * additional condition that must be met before the block body is executed.
    * Note that the presence of a TO or WHILE does not make this a loop. If
    * neither the TO clause or WHILE expression is specified, this is a
    * simple block. If both are specified then both of the conditions are
    * tested with a logical AND. By default, the ON ENDKEY UNDO, LEAVE and ON
    * ERROR UNDO, RETRY properties are supported.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself or if there
    * is a TO or WHILE clause then the query processing should be located in
    * the {@link Block#enter} method.  This means that the caller is
    * responsible for all query processing. The record retrieval must be done
    * on the first line of code in the block or in the <code>enter</code>
    * method to duplicate the Progress behavior. Note that this is required
    * to handle all error cases and 4GL conditions properly.
    * <p>
    * The evaluation of the TO or WHILE block termination conditions is done
    * AFTER the record retrieval.  This causes any found record to remain
    * available if the block is never entered because of the TO or WHILE
    * conditions.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    * @param    query
    *           query that will iterate forBlock.
    * @param    direction
    *           direction in which query will be iterating.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to                        
    *           The TO clause that defines the block condition. The block
    *           control variable is initialized before entering the block. 
    *           Before the block body is entered, the control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at that moment). if the termination condition is
    *           met, the block is never entered.
    * @param    expr      
    *           The WHILE clause that defines a block condition. This
    *           expression is evaluated before the block body is about to
    *           be entered.  The block body will be entered unless the
    *           expression evaluates to <code>false</code>.
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   private static void forBlockWorker(TransactionType lvl,
                                      P2JQuery        query,
                                      int             direction, 
                                      String[]        enclosing,
                                      String          label,
                                      ToClause        to,
                                      LogicalOp       expr,
                                      OnPhrase[]      on,
                                      Block           block)
   {
      // give the block a chance to handle any initialization which must happen BEFORE the TM
      // scope is pushed; doesn't repeat on retry
      block.pre();
      query.setLenientOffEnd(true);
      
      BlockType btype = null;
      
      if (to == null)
      {
         btype = (expr == null) ? BlockType.FOR_BLOCK : BlockType.FOR_BLOCK_WHILE;
      }
      else
      {
         btype = (expr == null) ? BlockType.FOR_BLOCK_TO : BlockType.FOR_BLOCK_TO_WHILE;
      }
      
      OnPhrase[] defOn = new OnPhrase[2];
      defOn[0] = new OnPhrase(Condition.ENDKEY, Action.LEAVE, label);
      defOn[1] = new OnPhrase(Condition.ERROR, Action.RETRY, label);
      
      int ttype = convertTransType(lvl, btype);
      int props = decodeConditions(defOn, on);
      
      WorkArea wa = work.obtain();

      wa.tm.pushScope(label, ttype, props, false, false, false, false, btype);
      
      try
      {
         try
         {
            // each constructed query during block initialization will be
            // collected
            wa.tm.startOffEndRegistration();
            
            // give the block a chance to initialize its state and don't
            // repeat that during retry
            block.init();
         }
         finally
         {
            // after block initialization is finished, the off end listeners
            // for all the buffers in the collected queries are saved
            wa.tm.stopOffEndRegistration();
         }

         wa.tm.blockSetup();

         blockLabel:
         do
         {
            try
            {
               boolean querySucceful = false;
               switch (direction) 
               {
                  case QueryConstants.FIRST: {
                     querySucceful = query.first();
                     break;                
                  }
                  case QueryConstants.LAST: {
                     querySucceful = query.last();
                     break;
                  }
                  case QueryConstants.UNIQUE: {
                     querySucceful = query.unique();
                     break;
                  }
                  case QueryConstants.ITERATE: {
                     querySucceful = query.next();
                     break;
                  }
               }
        
          
               if (!querySucceful) 
               {
                  wa.tm.notifyCondition(Condition.ENDKEY);
                  try
                  {
                     wa.tm.processOffEndListeners(true);
                     // avoid roll-back; the query initialization might have done some database work
                     // like honoring the RecordNursery. If the query didn't find any record, using a rollback
                     // will eliminate the work done in the init block (i.e. a side-effect aggressive flush).
                     break blockLabel;
                  }
                  finally
                  {
                     wa.tm.processOffEndListeners(false);
                  }
               }
               
               if (processForBody(wa, block, to, expr, on, defOn))
               {
                  break blockLabel;
               }
            }
            
            catch (ConditionException ce)
            {
               wa.tm.notifyCondition(ce);
               
               // when there are no more records in the query, we ALWAYS
               // UNDO, LEAVE (which is the same as the default ENDKEY
               // processing) the current block even if the user has defined
               // an explicit behavior for ENDKEY
               if (ce instanceof QueryOffEndException)
               {
                  QueryOffEndException qoee = (QueryOffEndException) ce;
                  QueryOffEndListener[] listeners = qoee.getListeners();

                  // flag indicating if the off-end listeners are the one 
                  // registered during block initialization
                  boolean allOffEndListeners = true;
                  for (int i = 0; i < listeners.length; i++)
                  {
                     allOffEndListeners = allOffEndListeners && 
                                          wa.tm.isOffEndListener(listeners[i]);
                  }

                  if (allOffEndListeners)
                  {
                     try
                     {
                        // if the buffers are the ones used by the FOR block,
                        // process them and trigger an UNDO, LEAVE
                        wa.tm.processOffEndListeners(true);

                        wa.tm.rollback(label, ce);
                        break blockLabel;
                     }
                     finally
                     {
                        wa.tm.processOffEndListeners(false);
                     }
                  }
               }

               try
               {
                  // if the exception was triggered by something else, then
                  // the off-end interested buffers must remain on the 
                  // currently referenced record
                  wa.tm.processOffEndListeners(true);

                  // normal condition processing
                  switch (processCondition(wa, on, defOn, ce, enclosing, label))
                  {
                     // note that this is not an iterating block so a leave or
                     // next targeted at this block must always act the same
                     case BREAK:
                     case CONTINUE:
                        break blockLabel;
                     default:
                        break;
                  }
               }
               finally
               {
                  wa.tm.processOffEndListeners(false);
               }
            }
            
            catch (RetryUnwindException rue)
            {
               wa.tm.honorRetry(rue);
            }
            
            catch (LeaveUnwindException lue)
            {
               if (testLeave(wa, enclosing, label) == Disposition.BREAK)
               {
                  // the LEAVE targeted this block or an enclosing
                  // non-managed block
                  break blockLabel;
               }
               
               // the LEAVE must be referencing an enclosing block which IS
               // known to the block manager OR to one of the other enclosing
               // managed blocks, so keep unwinding the stack
               throw lue;
            }
            
            catch (NextUnwindException nue)
            {
               if (testNext(wa, enclosing, label) == Disposition.BREAK)
               {
                  // the NEXT can't be targeted at this block BUT it can be
                  // targeted at an enclosing non-managed block
                  break blockLabel;
               }
               
               // the NEXT must be referencing an enclosing block which IS
               // known to the block manager OR to one of the other enclosing
               // managed blocks, so keep unwinding the stack
               throw nue;
            }
            
            catch (ReturnUnwindException rue)
            {
               // RETURN can't be targeted at a DO block so keep unwinding
               throw rue;
            }
            
            catch (Throwable thr)
            {
               wa.tm.abnormalEnd(thr);
            }
         }
         while (wa.tm.needsRetry());
      }
      
      finally
      {
         wa.tm.popScope();
      }
   }
   
   /**                   
    * Execute a FOR EACH, FOR EACH WHILE block, FOR EACH TO block
    * or FOR EACH TO WHILE block with the given configuration and
    * with default properties.  Any TO or WHILE clause is treated as an
    * additional condition that must be met before the loop body is executed.
    * If both are specified then both of the conditions are tested with a 
    * logical AND. By default, the ON ENDKEY UNDO, LEAVE and ON ERROR UNDO,
    * RETRY properties are supported.
    * <p>
    * The record retrieval that is associated with FOR blocks or loops must
    * be implemented directly inside the code of the block itself or if there
    * is a TO or WHILE clause then the query processing should be located in
    * the {@link Block#enter} method.  This means that the caller is
    * responsible for all query processing. The record retrieval must be done
    * on the first line of code in the block or in the <code>enter</code>
    * method to duplicate the Progress behavior. Note that this is required
    * to handle all error cases and 4GL conditions properly.
    * <p>
    * The evaluation of the TO or WHILE block termination conditions is done
    * AFTER the record retrieval.  This causes any found record to remain
    * available if the loop is never entered (or re-entered) because of the
    * TO or WHILE conditions.
    *
    * @param    lvl
    *           The transaction level to be honored. 
    *           @param    query
    *           query that will iterate forEachBlock.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends.
    * @param    expr      
    *           The WHILE clause that defines a loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>. 
    * @param    on
    *           List of user-defined on phrases.
    * @param    block
    *           The code to execute.
    */
   private static void forEachWorker(TransactionType lvl,
                                     P2JQuery        query,
                                     String[]        enclosing,
                                     String          label,
                                     ToClause        to,
                                     LogicalOp       expr,
                                     OnPhrase[]      on,
                                     Block           block)
   {
      // give the block a chance to handle any initialization which must happen BEFORE the TM
      // scope is pushed; doesn't repeat on retry
      block.pre();
      query.setLenientOffEnd(true);
      query.setIterating(true);
      
      BlockType btype = null;
      
      if (to == null)
      {
         btype = (expr == null) ? BlockType.FOR_LOOP : BlockType.FOR_LOOP_WHILE;
      }
      else
      {
         btype = (expr == null) ? BlockType.FOR_LOOP_TO : BlockType.FOR_LOOP_TO_WHILE;
      }
      
      OnPhrase[] defOn = new OnPhrase[2];
      defOn[0] = new OnPhrase(Condition.ENDKEY, Action.LEAVE, label);
      defOn[1] = new OnPhrase(Condition.ERROR, Action.RETRY, label);
      
      int ttype = convertTransType(lvl, btype);
      int props = decodeConditions(defOn, on);
      
      WorkArea wa = work.obtain();
      
      wa.tm.pushScope(label, ttype, props, false, false, true, true, btype);
      
      try
      {
         try
         {
            // each constructed query during block initialization will be
            // collected
            wa.tm.startOffEndRegistration();
            
            // give the block a chance to initialize its state and don't
            // repeat that during retry
            block.init();
         }
         finally
         {
            // after block initialization is finished, the off end listeners
            // for all the buffers in the collected queries are saved
            wa.tm.stopOffEndRegistration();
            // after all queries were created and registered, they must be
            // reset so the buffers reference no record.
            if (!query.isPresort())
            {
               Set<QueryOffEndListener> listeners = wa.tm.getOffEndListeners(false);
               
               for (QueryOffEndListener qoel : listeners)
               {
                  qoel.reset();
               }
            }
         }

         boolean topQuerySuccessful;
         loop:
         while (true)
         {
            wa.tm.blockSetup();
            topQuerySuccessful = false;

            do
            {  
               try
               {  
                  if (!query.next())
                  {
                     wa.tm.notifyCondition(Condition.ENDKEY);
                     try
                     {
                        wa.tm.processOffEndListeners(true);
                        // avoid roll-back; the query initialization might have done some database work
                        // like honoring the RecordNursery. If the query didn't find any record, using a rollback
                        // will eliminate the work done in the init block (i.e. a side-effect aggressive flush).
                        break loop;
                     }
                     finally
                     {
                        wa.tm.processOffEndListeners(false);
                     }
                  }
                  topQuerySuccessful = true;

                  if (processForBody(wa, block, to, expr, on, defOn))
                  {
                     break loop;
                  }
               }
               
               catch (ConditionException ce)
               {
                  if (ce.shouldExitBlock() && !topQuerySuccessful)
                  {
                     // an error was produced when executing the FOR-EACH query
                     // leave the block instead of retrying
                     try
                     {
                        wa.tm.processOffEndListeners(true);
                        break loop;
                     }
                     finally
                     {
                        wa.tm.processOffEndListeners(false);
                     }
                  }

                  wa.tm.notifyCondition(ce);
                  
                  if (ce instanceof QueryOffEndException)
                  {
                     QueryOffEndException qoee = (QueryOffEndException) ce;
                     QueryOffEndListener[] listeners = qoee.getListeners();

                     // flag indicating if the off-end listeners are the one 
                     // registered during block initialization
                     boolean allOffEndListeners = true;
                     for (int i = 0; i < listeners.length; i++)
                     {
                        allOffEndListeners = allOffEndListeners && 
                                             wa.tm.isOffEndListener(listeners[i]);
                     }

                     if (allOffEndListeners)
                     {
                        try
                        {
                           // if the buffers are the ones used by the FOR block,
                           // process them and trigger an UNDO, LEAVE
                           wa.tm.processOffEndListeners(true);

                           wa.tm.rollback(label, ce);
                           break loop;
                        }
                        finally
                        {
                           wa.tm.processOffEndListeners(false);
                        }
                     }
                  }
                  
                  try
                  {
                     // if the exception was triggered by something else, then
                     // the off-end interested buffers must remain on the 
                     // currently referenced record
                     wa.tm.processOffEndListeners(true);

                     // normal condition processing
                     switch (processCondition(wa, on, defOn, ce, enclosing, label))
                     {
                        case BREAK:
                           break loop;
                        case CONTINUE:
                           continue loop;
                        default:
                           break;
                     }
                  }
                  finally
                  {
                     wa.tm.processOffEndListeners(false);
                  }
               }
               
               catch (RetryUnwindException rue)
               {
                  wa.tm.honorRetry(rue);
               }
               
               catch (LeaveUnwindException lue)
               {
                  if (testLeave(wa, enclosing, label) == Disposition.BREAK)
                  {
                     // the LEAVE targeted this block or an enclosing non-managed block
                     break loop;
                  }
                  
                  // the LEAVE must be referencing an enclosing block which IS
                  // known to the block manager OR to one of the other
                  // enclosing managed blocks, so keep unwinding the stack
                  throw lue;
               }
               
               catch (NextUnwindException nue)
               {
                  switch (testNext(wa, enclosing, label))
                  {
                     case BREAK:
                        // the NEXT is targeted at an enclosing non-managed block
                        break loop;
                        
                     case CONTINUE:
                        // the NEXT is targeted at the current loop
                        continue loop;
                        
                     default:
                        break;
                  }
                  
                  // the NEXT must be referencing an enclosing block which IS
                  // known to the block manager OR to one of the other
                  // enclosing managed blocks, so keep unwinding the stack
                  throw nue;
               }
               
               catch (ReturnUnwindException rue)
               {
                  // RETURN can't be targeted at a DO block so keep unwinding
                  throw rue;
               }
               
               catch (Throwable thr)
               {
                  wa.tm.abnormalEnd(thr);
               }
            }
            while (wa.tm.needsRetry());
            
            if (wa.tm.isBreakPending())
            {
               break loop;
            }
         }
      }
      
      finally
      {
         wa.tm.popScope();
      }
   }
   
   /**
    * Test the given expressions to determine if the calling loop should
    * iterate or if the loop should exit.  Either or both parameters
    * may be <code>null</code> individually or simultaneously.
    *
    * @param    to
    *           The TO clause that defines a loop condition. The loop control
    *           variable is initialized on the first pass through and on
    *           subsequent passes it is incremented by a given factor. Before
    *           the loop body is entered, the loop control variable is
    *           compared to the termination value (which is dynamically
    *           resolved at each loop iteration). When the termination
    *           condition is met, the loop ends. If this is <code>null</code>,
    *           then a WHILE clause MUST be present to provide the condition
    *           for maintaining the loop.
    * @param    expr      
    *           The WHILE clause that defines a loop condition. This
    *           expression is evaluated every time the loop body is about to
    *           be entered.  The loop body will be entered unless the
    *           expression evaluates to <code>false</code>. If this is
    *           <code>null</code>, then a TO clause MUST be present to
    *           provide the condition for maintaining the loop.
    *
    * @return   <code>true</code> if all non-null parameters evaluate to
    *           <code>true</code> or if both parameters are <code>null</code>.
    */
   private static boolean needsIterate(ToClause to, LogicalOp expr)
   {
      // in a TO WHILE case (where both conditions are specified), the 4GL evaluates the TO condition first
      // and then conditionally evaluates the WHILE if needed; the use of && here intentionally
      // short-circuits the WHILE expression if the TO is false
      return (to == null || to.incrementAndTest()) && (expr == null || expr.evaluate().booleanValue());
   }
   
   /**
    * Check if any CATCH blocks defined at the current enclosing block can manage this exception.
    * <p>
    * If none found, ignore this exception.  4GL doesn't seem to propagate the errors further than
    * then current block.
    * <p>
    * If a CATCH block is found, then execute it.
    * 
    * @param    wa
    *           Context local data or {@code null} if not available in the caller.
    * @param    lex
    *           The thrown legacy error.
    * @param    on
    *           List of user-defined ON phrases.  May be {@code null}.
    * @param    defOn
    *           List of implicit ON phrases for this block.  May be {@code null}.
    * 
    * @throws   LegacyErrorException
    *           If the processing needs to be deferred.
    */
   private static void processLegacyError(WorkArea wa, LegacyErrorException lex, OnPhrase[] on, OnPhrase[] defOn)
   {
      ObjectVar<? extends LegacyError> error = lex.getError();
      if (error.isUnknown())
      {
         return;
      }
      
      boolean implicit = (on == null);
      if (implicit)
      {
         on = defOn;
      }
      
      LegacyError legacyError = error.ref;
      Class<?> errCls = legacyError.getClass();

      boolean isFromReturn = wa.tm.getBlock().wasReturnError;
      boolean mustManage = mustManageLegacyError(wa);
      // do not throw if we are exiting a top-level block
      boolean canThrow = mustManage || isFromReturn || (lex.isExplicit() && !wa.tm.isTopLevelBlock());
      boolean noThrowOnError = false;
      if (on != null && wa.tm.hasErrorProp() && (!implicit || !mustManage))
      {
         OnPhrase imple = matchCondition(on, null, Condition.ERROR);
         if (imple != null)
         {
            canThrow = canThrow || (imple.action == Action.THROW);
            noThrowOnError = (imple.action != Action.THROW);
         }
      }
      
      int i = 0;
      int topLvlBlocks = 0;
      BlockDefinition block = wa.tm.getBlock(i);
      if (isFromReturn)
      {
         // skip all CATCH blocks from current top-level block
         while (block != null && !block.topLevel)
         {
            i = i + 1;
            block = wa.tm.getBlock(i);
         }
         if (block != null)
         {
            i = i + 1;
            block = wa.tm.getBlock(i);
         }
         
         lex.setFromReturn(false);
      }
      while (block != null)
      {
         topLvlBlocks += (block.topLevel ? 1 : 0);
         
         if (block.catchBlocks != null)
         {
            for (Class<?> cls : block.catchBlocks.keySet())
            {
               if (cls.isAssignableFrom(errCls))
               {
                  if (!canThrow && topLvlBlocks > 1)
                  {
                     displayErrorMessage(wa.tm, legacyError, 1, true, true, false);

                     // we need a decrement here, as the instance is also 'hooked' by LegacyErrorException
                     error.decrement();
                     
                     // release the reference
                     error.set(null);
                     
                     return;
                  }
                  if (i == 0)
                  {
                     BlockDefinition blk = block;
                     String label = blk.label;
                     wa.tm.setupCatchProcessing(() ->
                     {
                        try
                        {
                           // clear any pending errors
                           wa.tm.errHlp.clearPending();
                           Block catchBlock = new Block()
                           {
                              @Override
                              public void body()
                              {
                                 wa.tm.getBlock().type = BlockType.CATCH;
                                 blk.catchBlocks.get(cls).accept(error);
                              }
                           };
                           doTerminationBlockWorker(wa, 
                                                    TransactionType.NONE, 
                                                    CATCH_BLOCK_LABEL + label,
                                                    false,
                                                    catchBlock);
                        }
                        finally
                        {
                           // we need a decrement here, as the instance is also 'hooked' by LegacyErrorException
                           error.decrement();
                           
                           // release this reference
                           error.set(null);
                        }
                     });
                     
                     // the error was registered, will be processed in popScope, undo and leave the block
                     undoLeave("", "");
                     return;
                  }
                  else if (noThrowOnError)
                  {
                     throw new ErrorConditionException(error.ref.getMessage(new integer(1)).toStringMessage());
                  }
                  else if (canThrow)
                  {
                     // this is re-thrown, so mark it as 'explicit'
                     lex.setExplicit(true);
                     throw lex;
                  }
               }
            }
         }
         
         i = i + 1;
         block = wa.tm.getBlock(i);
      }

      if (noThrowOnError)
      {
         throw new ErrorConditionException(error.ref.getMessage(new integer(1)).toStringMessage());
      }
      
      if (canThrow)
      {
         displayErrorMessages(wa.tm, legacyError, false, true);
         throw lex;
      }
         
      // release it was not found, and is from a RETURN ERROR statement
      if (isFromReturn)
      {
         if (ErrorManager.isPending())
         {
            throw lex;
         }
         displayErrorMessage(wa.tm, legacyError, 1, true, true, false);
      }
      else
      {
         displayErrorMessages(wa.tm, legacyError, true, false);
      }
      
      // we need a decrement here, as the instance is also 'hooked' by LegacyErrorException
      error.decrement();

      // release the reference
      error.set(null);

      if (lex.isFromReturn())
      {
         leave(wa, "");
      }
   }

   /**
    * Returns if the legacy error needs to be displayed based on several criteria: if the error has already
    * been displayed, if this is part of the top block execution and if it's a silent block (suppressed 
    * error).
    * 
    * @param    tm
    *           The transaction helper with information about the block. 
    * @param    legacyError
    *           The error to be displayed. 
    *
    * @return   See above.
    */
   private static boolean shouldDisplayError(TransactionHelper tm, LegacyError legacyError)
   {
      return !legacyError._isDisplayed() && tm.isTopLevelBlock() && !tm.isSuppressError();
   }

   /**
    * Displays all messages of the legacy error if it is eligible for display, and then marks the error as 
    * displayed.
    *
    * @param    tm
    *           The transaction helper with information about the block. 
    * @param    legacyError
    *           The error to be displayed.
    * @param    addCallStack
    *           Flag to indicate if callstack needs to be added to the message.
    * @param    onlyLog
    *           Flag to record a log instead of displaying the error.
    */
   private static void displayErrorMessages(TransactionHelper tm,
                                            LegacyError legacyError,
                                            boolean addCallStack,
                                            boolean onlyLog)
   {
      if (!shouldDisplayError(tm, legacyError))
      {
         return;
      }
      for (int i = 0; i < legacyError.getNumMessages().intValue(); i++)
      {
         displayErrorMessage(tm, legacyError, i + 1, false, addCallStack, onlyLog);
      }
      legacyError._setDisplayed();
   }

   /**
    * Displays the message on the selected index of the legacy error, if the error is eligible for display, 
    * and marks the error as displayed, if needed.
    *
    * @param    tm
    *           The transaction helper with information about the block. 
    * @param    legacyError
    *           The error to be displayed.
    * @param    markDisplayed
    *           Flag to indicate if the error should be marked as displayed.
    * @param    addCallStack
    *           Flag to indicate if callstack needs to be added to the message.
    * @param    onlyLog
    *           Flag to record a log instead of displaying the error.
    */
   private static void displayErrorMessage(TransactionHelper tm,
                                           LegacyError legacyError,
                                           int msgIndex,
                                           boolean markDisplayed,
                                           boolean addCallStack,
                                           boolean onlyLog)
   {
      character errMsg = legacyError.getMessage(new integer(msgIndex));
      String errMsgString = errMsg.toJavaType();

      if (!StringHelper.hasContent(errMsgString) || !shouldDisplayError(tm, legacyError))
      {
         return;
      }

      if (markDisplayed)
      {
         legacyError._setDisplayed();
      }

      if (onlyLog)
      {
         ErrorManager.writeLog(errMsgString);
      }
      else if (addCallStack)
      {
         ErrorManager.displayError(errMsgString);
      }
      else
      {
         ErrorManager.displayError(errMsgString, false, null, false);
      }
   }
   
   /**
    * Check if any CATCH blocks defined at the current enclosing block can manage thisSTOP exception.
    * <p>
    * If a CATCH block is found, then execute it.
    * 
    * @param    wa
    *           Context local data or {@code null} if not available in the caller.
    * @param    lex
    *           The thrown legacy error.
    * 
    * @throws   LegacyErrorException
    *           If the processing needs to be deferred.
    */
   private static void processLegacyStop(WorkArea wa, LegacyStopException lex)
   {
      ObjectVar<? extends Stop> error = lex.getError();
      if (error.isUnknown())
      {
         return;
      }
      
      Stop legacyStop = error.ref;
      Class<?> stopCls = legacyStop.getClass();

      boolean mustManage = mustManageLegacyStop(wa);
      // do not throw if we are exiting a top-level block
      boolean canThrow = mustManage;
      boolean noThrowOnError = !mustManage;
      
      int i = 0;
      BlockDefinition block = wa.tm.getBlock(i);
      
      while (block != null)
      {
         if (block.catchBlocks != null)
         {
            for (Class<?> cls : block.catchBlocks.keySet())
            {
               if (cls.isAssignableFrom(stopCls))
               {
                  if (i == 0)
                  {
                     BlockDefinition blk = block;
                     wa.tm.setupCatchProcessing(() ->
                     {
                        // clear any pending errors
                        wa.tm.errHlp.clearPending();
                           
                        Block catchBlock = new Block()
                        {
                           @Override
                           public void body()
                           {
                              wa.tm.getBlock().type = BlockType.CATCH;
                              blk.catchBlocks.get(cls).accept(error);
                           }
                        };
                        doTerminationBlockWorker(wa, 
                                                 TransactionType.NONE, 
                                                 CATCH_BLOCK_LABEL,
                                                 false,
                                                 catchBlock);
                     });
                     
                     if (error.ref instanceof StopAfter)
                     {
                        wa.tm.setupStopAfterProccessing(lex);
                     }
                     
                     // the error was registered, will be processed in popScope, undo and leave the block
                     undoLeave("", "");
                     return;
                  }
                  else if (noThrowOnError)
                  {
                     throw new StopConditionException("Thread was asynchronously interupted");
                  }
                  else if (canThrow)
                  {
                     // this is re-thrown, so mark it as 'explicit'
                     throw lex;
                  }
               }
            }
         }
         
         i = i + 1;
         block = wa.tm.getBlock(i);
      }

      // we need a decrement here, as the instance is also 'hooked' by LegacyErrorException
      error.decrement();

      // release the reference
      error.set(null);
      
      throw new StopConditionException("Thread was asynchronously interupted");
   }
   
   /**
    * Check if any CATCH blocks defined at the specified enclosing block can manage this exception.
    * <p>
    * If none found, ignore this exception.  4GL doesn't seem to propagate the errors further than
    * then current block.
    * 
    * @param    wa
    *           Context local data or {@code null} if not available in caller.
    * @param    type
    *           The error type to process.
    * @param    levels
    *           Flag indicating which block to use (0 for current, 1 for parent, etc).  Use -1 to search the
    *           entire stack.
    * 
    * @return   <code>true</code> if this exception can be processed by the current block.
    */
   private static boolean hasLegacyError(WorkArea                     wa,
                                         Class<? extends LegacyError> type,
                                         int                          levels)
   {
      if (wa == null)
      {
         wa = work.obtain();       
      }
      
      for (int i = (levels == -1 ? 0 : levels); i <= (levels == -1 ? wa.tm.getNestingLevel() - 1 : levels); i++)
      {
         BlockDefinition block = wa.tm.getBlock(i);
         
         // Note: block can be null when this method is called from JUnit
         if (block == null || block.catchBlocks == null || block.catchBlocks.isEmpty())
         {
            continue;
         }
         
         for (Class<?> cls : block.catchBlocks.keySet())
         {
            if (cls.isAssignableFrom(type))
            {
               return true;
            }
         }
      }
      
      return false;
   }
   
   /**
    * Check if any CATCH blocks defined at the specified enclosing block can manage this STOP exception.
    * <p>
    * If none found, on the path upward. But a ON STOP phrase is found of the block, then it takes precedence. 
    * 
    * @param    wa
    *           Context local data or {@code null} if not available in caller.
    * @param    type
    *           The error type to process.
    * @param    levels
    *           Flag indicating which block to use (0 for current, 1 for parent, etc).  Use -1 to search the
    *           entire stack.
    * 
    * @return   <code>true</code> if this exception can be processed by the current block.
    */
   private static boolean hasLegacyStop(WorkArea              wa,
                                        Class<? extends Stop> type)
   {
      if (wa == null)
      {
         wa = work.obtain();         
      }
      
      boolean throwInCatch = wa.tm.getBlock().type == BlockType.CATCH;
      
      for (int i = throwInCatch ? 2 : 0; i <= wa.tm.getNestingLevel() - 1; i++)
      {
         BlockDefinition block = wa.tm.getBlock(i);
         
         // Note: block can be null when this method is called from JUnit
         if (block == null || block.catchBlocks == null || block.catchBlocks.isEmpty())
         {
            if (testProps(block.props, Condition.STOP))
            {
               return false;
            }
            
            continue;
         }
         
         for (Class<?> cls : block.catchBlocks.keySet())
         {
            if (type.isAssignableFrom(cls))
            {               
               return true;
            }
         }
      }
      
      return false;
   }
   
   /**
    * Make sure that the legacy exception is honoring the roll-back of transactions
    * in the current block. For now, this is not honoring the labeling of undo statements.
    * 
    * @param   wa
    *          Context local data or {@code null} if not available in the caller.
    * @param   e
    *          The legacy error exception that caused the unwinding.
    */
   private static void processLegacyException(WorkArea wa, LegacyErrorException e)
   {
      BlockDefinition blk = wa.tm.getBlock();

      if (!blk.undoThrow)
      {
         wa.tm.errHlp.setPending(false);
         wa.tm.attemptRollback();
      }

      blk.undoThrow = false;
      throw e;
   }
   
   /**
    * Make sure that the legacy stop exception is further thrown.
    * 
    * @param   wa
    *          Context local data or {@code null} if not available in the caller.
    * @param   e
    *          The legacy stop exception that caused the unwinding.
    */
   private static void processLegacyStopException(WorkArea wa, LegacyStopException e)
   {
      BlockDefinition blk = wa.tm.getBlock();

      if (!blk.undoThrow)
      {
         wa.tm.attemptRollback();
      }

      blk.undoThrow = false;
      throw e;
   }
   
   /**
    * Core worker to handle all the possible behavior in response to a
    * condition being raised in an inner block (DO, REPEAT or FOR). The
    * given condition exception will first be matched with the user-defined
    * on phases and then if no match is found, with the default on phrases
    * for the calling block. If nothing is found, then the condition
    * exception will be re-thrown. If a match is found then condition-specific
    * processing will be done to UNDO and then either unwind the stack using
    * exceptions or a disposition will be returned so that the caller can
    * properly implement a LEAVE or NEXT that is targetted at the current
    * block or at an enclosing non-managed block.
    * <p>
    * This honors infinite loop protection for converting NEXT to LEAVE
    * based on runtime state.
    *
    * @param    wa
    *           Context local data or {@code null} if not available in the caller.
    * @param    user
    *           List of user-defined on phrases.
    * @param    def
    *           List of default on phrases for the current block type.
    * @param    ce
    *           The condition being raised.
    * @param    enclosing
    *           The list of non-managed block names that enclose the current
    *           block.
    * @param    label
    *           The block name of the current block.
    *
    * @return   If an exception is not thrown (or re-thrown), then the caller
    *           will get a disposition code that should be honored to
    *           properly implement a LEAVE or NEXT action.
    */
   private static Disposition processCondition(WorkArea           wa,
                                               OnPhrase[]         user,
                                               OnPhrase[]         def,
                                               ConditionException ce,
                                               String[]           enclosing,
                                               String             label)
   throws ConditionException,
          StackUnwindException,
          RetryUnwindException
   {
      if (def != null                   && 
         (wa.pm.isBlockLevelUndoThrow() ||
          wa.tm.isTopLevelDatabaseTrigger()))
      {
         // change default ERROR, <action> to ERROR, THROW if BLOCK-LEVEL ON ERROR UNDO, THROW
         for (OnPhrase on : def)
         {
            if (on.condition == Condition.ERROR)
            {
               on.action = Action.THROW;
            }
         }
      }

      Condition current = exceptionToCondition(ce);
      OnPhrase imple    = matchCondition(user, def, current);
      
      if (imple != null)
      {
         // ERROR processing has a special mode (RETURN ERROR) and STOP
         // processing mode which must unwind the stack to a specific
         // point, so we must check if we are in either of those modes now
         // (before the UNDO or secondary action for the block can be
         // executed)
         if (current == Condition.ERROR)
         {
            ErrorConditionException err = (ErrorConditionException) ce;
            
            // END-ERROR is propagated to the parent block in blocks that
            // have the ERROR property but do NOT have the ENDKEY property
            if (err.isEndError() && !wa.tm.hasEndkeyProp())
            {
               // detect the case in which a END-ERROR would have been
               // converted to ENDKEY, in such a case we must rethrow
               if (wa.tm.getInteractions() < 2)
               {
                  // let the parent see this (this will re-throw the
                  // exception after handling rollback state/processing)
                  wa.tm.abnormalEnd(err, false);
               }
            }
            
            // if we must unwind, this call will re-throw the exception,
            // otherwise it will return and we can continue with "normal"
            // exception processing
            wa.tm.honorError((ErrorConditionException) ce);
         }
         else if (current == Condition.STOP)
         { 
            // if we must unwind, this call will re-throw the exception,
            // otherwise it will return and we can continue with "normal"
            // exception processing
            wa.tm.honorStop((StopConditionException) ce);
            
            // on stop condition triggered by stop-after timer,
            // right block should be targeted
            StopAfterTimer stopAfterTimer = wa.stopAfterTimer;
            if (stopAfterTimer != null && stopAfterTimer.isStopAfterConditionRaised())
            {
               if (!stopAfterTimer.isStoppedBlock(wa.tm.getBlock()))
               {
                  throw ce;
               }
               else
               {
                  stopAfterTimer.cleanUp();
               }
            }
         }
         
         // first we UNDO at the specified label (which may be null meaning
         // we UNDO the current block)
         if (imple.condition == Condition.QUIT_COMMIT)
         {
            // let the action proceed without rollback
         }
         else
         {
            wa.tm.rollback(imple.undoLabel);
         }
         
         Action target = imple.action;
         
         // honor ILP for NEXT
         if (target == Action.NEXT)
         {
            if (!wa.tm.honorNext(imple.actionLabel))
            {
               // convert to a LEAVE
               target = Action.LEAVE;
            }
         }
         
         // second we implement the specified action
         switch (target)
         {
            case THROW:
               if (ce instanceof LegacyErrorException)
               {
                  throw (LegacyErrorException) ce;
               }
               else if (ce instanceof ErrorConditionException)
               {
                  throw (ErrorConditionException) ce;
               }
               break;
            
            case LEAVE:
               if (imple.actionLabel == null        || 
                   imple.actionLabel.length() == 0  ||
                   imple.actionLabel.equals(label))
               {
                  return Disposition.BREAK;
               }
               else
               {
                  // at this point we must have a non-null and non-empty
                  // label that is the leave target
                  wa.deferredLeave = imple.actionLabel;
                  
                  if (matches(enclosing, imple.actionLabel))
                  {
                     // the target is a non-managed block that directly
                     // encloses the current block, break out and let the
                     // calling code check to see that this needs to be
                     // honored
                     return Disposition.BREAK;
                  }
                  else
                  {
                     // unwind the stack
                     throw wa.leaveExc;
                  }
               }
            case NEXT:            
               if (imple.actionLabel == null        || 
                   imple.actionLabel.length() == 0  ||
                   imple.actionLabel.equals(label))
               {
                  return Disposition.CONTINUE;
               }
               else
               {
                  // at this point we must have a non-null and non-empty
                  // label that is the next target
                  wa.deferredNext = imple.actionLabel;
                  
                  if (matches(enclosing, imple.actionLabel))
                  {
                     // the target is a non-managed block that directly
                     // encloses the current block, break out and let the
                     // calling code check to see that this needs to be
                     // honored
                     return Disposition.BREAK;
                  }
                  else
                  {
                     // unwind the stack
                     throw wa.nextExc;
                  }
               }
            case RETRY:
               // if this retry is being triggered by an ENDKEY, remember
               // that fact so that the retry processing can be customized
               // (this enables the "stuttering" quirk and some custom
               // behavior with PAUSE
               if (current == Condition.ENDKEY)
               {
                  wa.tm.markEndkeyRetry();
               }
               
               // RETRY is always targetted at the same block as UNDO
               wa.tm.triggerRetry(imple.undoLabel);
               
               return Disposition.NONE;
            case RETURN_NORMAL:
               // this will throw an exception, it is OK because this method
               // will always be called in the context of an inner block and
               // WILL NEVER be called directly from a top-level block
               returnWorker(wa, imple.value, ReturnType.NORMAL);
               break;
            case RETURN_CONSUME:
               // this will throw an exception, it is OK because this method
               // will always be called in the context of an inner block and
               // WILL NEVER be called directly from a top-level block
               returnWorker(wa, imple.value, ReturnType.CONSUME);
               break;
            case RETURN_ERROR:
               // this will throw an exception, it is OK because this method
               // will always be called in the context of an inner block and
               // WILL NEVER be called directly from a top-level block
               returnWorker(wa, imple.value, ReturnType.ERROR);
               break;
            default:
               break;
         }
      }
      
      StopAfterTimer stopAfterTimer = wa.stopAfterTimer;
      if (stopAfterTimer != null && stopAfterTimer.isStopAfterConditionRaised())
      {
         if (stopAfterTimer.isStoppedBlock(wa.tm.getBlock()))
         {
            stopAfterTimer.cleanUp();
         }
      }
      
      // no match so we just re-throw the exception and continue to unwind
      // the stack; but we must process it as an unexpected exception which
      // will maintain rollback state properly
      wa.tm.abnormalEnd(ce, false);
      
      // never reached because the code above will re-throw the exception
      return null;
   }

   /**
    * Translate exception into {@link Condition} code.
    * 
    * @param    ce
    *           Source exception.
    *          
    * @return   one of the {@link Condition} codes or <code>null</code> if no
    *           match is found.
    */
   static Condition exceptionToCondition(ConditionException ce)
   {
      Condition current = null;
      
      if (ce instanceof ErrorConditionException)
      {
         current = Condition.ERROR;
      }
      else if (ce instanceof EndConditionException)
      {
         current = Condition.ENDKEY;
      }
      else if (ce instanceof StopConditionException)
      {
         current = Condition.STOP;
      }
      else if (ce instanceof QuitConditionException)
      {
         current = Condition.QUIT;
      }
      
      return current;
   }
   
   /**
    * Find a matching condition in the user-defined on phrases or the default
    * on phrases for the block and return the on phrase that is matched. The
    * user-defined on phrases are searched first and only if there is no
    * match will the default on phrases be searched.
    *
    * @param    user
    *           The set of user-defined on phrases for the current block.
    * @param    def
    *           The set of default on phrases for the current block.
    * @param    cond
    *           The condition being matched.
    *
    * @return   The on phrase that defines the behavior to be implemented or
    *           <code>null</code> if there is no match in either list.
    */
   private static OnPhrase matchCondition(OnPhrase[] user, OnPhrase[] def, Condition cond)
   {
      if (cond == null)
      {
         return null;
      }
      
      if (user != null)
      {
         for (OnPhrase next : user)
         {
            if (next.condition == cond || (cond == Condition.QUIT && next.condition == Condition.QUIT_COMMIT))
            {
               return next;
            }
         }
      }
      
      if (def != null)
      {
         for (OnPhrase next : def)
         {
            if (next.condition == cond)
            {
               return next;
            }
         }
      }
      
      return null;
   }
   
   /**
    * Encode the conditions supported by this block as a bitfield.
    * <p>
    * The inputs are analyzed to match <code>Condition</code> values with
    * their corresponding bits in the <code>TransactionManager</code>
    * properties bitfield.
    * <p>
    * The bits are defined by {@link TransactionManager#PROP_NONE},
    * {@link TransactionManager#PROP_ERROR},
    * {@link TransactionManager#PROP_ENDKEY},
    * {@link TransactionManager#PROP_STOP} or
    * {@link TransactionManager#PROP_QUIT}.
    *
    * @param    user
    *           The set of user-defined on phrases for the current block.
    * @param    def
    *           The set of default on phrases for the current block.
    *
    * @return   The calculated bitmask with each bit set that matches one of
    *           the ON phrase conditions. <code>PROP_NONE</code> will be
    *           returned if both parameters are <code>null</code> and/or
    *           empty.
    */
   private static int decodeConditions(OnPhrase[] user, OnPhrase[] def)
   {
      int bits = PROP_NONE;
      
      if (user != null)
      {
         for (OnPhrase next : user)
         {
            bits |= conditionMask(next.condition);
         }
      }
      
      if (def != null)
      {
         for (OnPhrase next : def)
         {
            bits |= conditionMask(next.condition);
         }
      }
      
      return bits;
   }
   
   /**
    * Matches a <code>Condition</code> with its corresponding
    * <code>TransactionManager</code> constant.
    *
    * @param    props
    *           The calculated bitmask with each bit set that matches one of
    *           the ON phrase conditions.
    * @param    cond
    *           The condition to match.
    *
    * @return   <code>true</code> if the condition is present in the  bitmask,
    *           <code>false</code> otherwise.
    */
   public static boolean testProps(int props, Condition contition)
   {
      return (props & conditionMask(contition)) != 0;
   }
   
   /**
    * Matches a <code>Condition</code> with its corresponding
    * <code>TransactionManager</code> constant.
    *
    * @param    cond
    *           The condition to match.
    *
    * @return   The integer constant that represents the given condition.
    */
   private static int conditionMask(Condition cond)
   {
      int rc = PROP_NONE;
      
      switch (cond)
      {
         case ERROR:
            rc = PROP_ERROR;
            break;
         case ENDKEY:
            rc = PROP_ENDKEY;
            break;
         case STOP:
            rc = PROP_STOP;
            break;
         case QUIT:
            rc = PROP_QUIT;
            break;
         default:
            break;
      }
      
      return rc;
   }
   
   /**
    * Detect if the leave event is referencing this block OR if it is
    * referencing a directly enclosing block which is not managed by this
    * class.  In either case, the result will be to break out of the current
    * block.  In all other cases, the result will be to re-throw the exception
    * and cause the stack to unwind to the nearest enclosing managed block.
    * <p>
    * The target of the leave operation must have been stored in context
    * local data when the leave exception was thrown (which caused the
    * stack to unwind).
    * <p>
    * This method is called from within a catch block to determine how to
    * respond to the deferred leave operation for the current block.
    *
    * @param    wa
    *           Context local work area.  Must not be {@code null}.
    * @param    enclosing
    *           The list of non-managed blocks that directly enclose the
    *           current block.
    * @param    label
    *           The name of the current block.  If this matches the target of
    *           the deferred leave operation, then the current block must
    *           be left.
    *
    * @return   Either <code>BREAK</code> or <code>THROW</code>.
    */
   private static Disposition testLeave(WorkArea wa, String[] enclosing, String label)
   {
      // test if the LEAVE is destined for this block
      if (deferredLeaveWorker(wa, label))
      {
         // it is, so honor the LEAVE
         return Disposition.BREAK;
      }
      else
      {
         // handle of LEAVE on an enclosing block that is not one
         // of which the block manager is aware
         if (matches(enclosing, wa.deferredLeave))
         {
            return Disposition.BREAK;
         }
      }
      
      // the LEAVE must be referencing an enclosing block which IS known
      // to the block manager OR to one of the other enclosing managed
      // blocks, so keep unwinding the stack
      return Disposition.THROW; 
   }
   
   /**
    * Detect if the next event is referencing this block OR if it is
    * referencing a directly enclosing block which is not managed by this
    * class.  In the first case, the result will be to continue the current
    * block.  In the second case, the caller must break out of the current
    * block.  In all other cases, the result will be to re-throw the exception
    * and cause the stack to unwind to the nearest enclosing managed block.
    * <p>
    * The target of the next operation must have been stored in context
    * local data when the next exception was thrown (which caused the
    * stack to unwind).
    * <p>
    * This method is called from within a catch block to determine how to
    * respond to the deferred next operation for the current block.
    *
    * @param    wa
    *           Context local work area.  Must not be {@code null}.
    * @param    enclosing
    *           The list of non-managed blocks that directly enclose the
    *           current block.
    * @param    label
    *           The name of the current block.  If this matches the target of
    *           the deferred leave operation, then the current block must
    *           be left.
    *
    * @return   Either <code>BREAK</code>, <code>CONTINUE</code> or
    *           <code>THROW</code>.
    */
   private static Disposition testNext(WorkArea wa, String[] enclosing, String label)
   {
      // test if the NEXT is destined for this block
      if (deferredNextWorker(wa, label))
      {
         // it is, so honor the NEXT
         return Disposition.CONTINUE;
      }
      else
      {
         // handle of NEXT on an enclosing block that is not one
         // of which the block manager is aware
         if (matches(enclosing, wa.deferredNext))
         {
            return Disposition.BREAK;
         }
      }
      
      // the NEXT must be referencing an enclosing block which IS known
      // to the block manager OR to one of the other enclosing managed
      // blocks, so keep unwinding the stack
      return Disposition.THROW;
   }
   
   /**
    * Common worker to cleanup top-level block state just before exiting.
    *
    * @param    wa
    *           The local context.
    */
   private static void exitTopLevel(WorkArea wa)
   {
      wa.topType.pop();
      wa.deferredLeave = null;
      wa.deferredNext  = null;
   }
   
   /**
    * Preserve certain work area state before running the given code and then restore that state
    * afterward. The code may contain and/or invoke arbitrarily complex code and control flow.
    * Direct invocation (without the state backup/restore) would otherwise corrupt the current
    * work area state.
    *
    * @param    wa
    *           Context local data or {@code null} if not available in the caller.
    * @param    code
    *           The code to execute.
    */
   private static void executeStateManaged(WorkArea wa, Runnable code)
   {
      // preserve current work area state
      ReturnType rtype = wa.rtype;
      String deferredLeave = wa.deferredLeave;
      String deferredNext = wa.deferredNext;
      boolean pendingDynCall = wa.pendingDynCall;
      
      // set a clean slate for validate processing
      wa.rtype = null;
      wa.deferredLeave = null;
      wa.deferredNext = null;
      wa.pendingDynCall = false;
      
      try
      {
         code.run();
      }
      
      finally
      {
         // restore previous state
         wa.rtype = rtype;
         wa.deferredLeave = deferredLeave;
         wa.deferredNext = deferredNext;
         wa.pendingDynCall = pendingDynCall;
      }
   }
   
   /**
    * Set the return value for the nearest enclosing function. This should only be called if the
    * nearest enclosing top-level block is a {@code FUNCTION}. Multiple calls to this before
    * returning from the function block will cause the value passed on the last call to be
    * honored.
    *
    * @param   bdt
    *          The return value to set. Passing {@code null} will reset the return value to
    *          {@code unknown}.
    * @param   wa
    *          The current context's data or {@code null} to force a lookup of the context data.
    * @param   nearest
    *          The nearest top-level block. Should be a FUNCTION block. Pass {@code null} to
    *          use the context data to find the block.
    */
   private static void setFuncReturn(Object bdt, WorkArea wa, BlockType nearest)
   {
      if (bdt == null)
      {
         return;
      }
      
      // replace the current latest value with the given instance
      if (wa == null)
      {
         wa = work.obtain();
      }
      if (nearest == null)
      {
         nearest = topLevelType(wa);
      }
      if (nearest == BlockType.FUNCTION)
      {
         if (wa.funcRet.size() > 0)
         {
            wa.funcRet.pop();          
            wa.funcRet.push(bdt);
            
            Class<?> rclass = bdt.getClass();
            if (rclass.isArray() && rclass.getComponentType() == object.class)
            {
               for (object<?> obj : (object[]) bdt)
               {
                  if (obj == null || obj.isUnknown())
                  {
                     continue;
                  }
                  
                  _BaseObject_ ref = obj.ref;
                  // mark this object as a pending assign - it will not be implicitly deleted
                  // if it's current referent gets out of scope 
                  wa.objHelper.pendingAssign(ref);
               }
            }
            else if (bdt instanceof object)
            {
               if (!((object) bdt).isUnknown())
               {
                  _BaseObject_ ref = ((object) bdt).ref;
                  // mark this object as a pending assign - it will not be implicitly deleted
                  // if it's current referent gets out of scope
                  wa.objHelper.pendingAssign(ref);
               }
            }
         }
      }
   }
   
   /**
    * Given a list of strings, detect if the given entry matches (case
    * sensitively) any of the elements in the list.
    *
    * @param    list
    *           The list of strings to check against.
    * @param    entry
    *           The element for which to search.
    *
    * @return   <code>true</code> if the given entry is found in the given
    *           list.
    */
   private static boolean matches(String[] list, String entry)
   {
      if (list == null || entry == null)
         return false;
      
      for (String element : list)
      {
         if (entry.equalsIgnoreCase(element))
         {
            return true;
         }
      }
         
      return false;
   }
   
   /**
    * Helper to convert between this class' enum and the corresponding {@link TransactionManager} constants.
    *
    * @param    ttype
    *           The enum to convert.
    * @param    btype
    *           The block type.
    *
    * @return   The corresponding {@link TransactionManager} constant.
    */
   private static int convertTransType(TransactionType ttype, BlockType btype)
   {
      int newType = -1;
      
      switch (ttype)
      {
         case NONE:
            newType = NO_TRANSACTION;
            break;
         case SUB:
            newType = SUB_TRANSACTION;
            break;
         case FULL:
            newType = TRANSACTION;
            break;
         default:
            break;
      }
      
      return newType;
   }
   
   /**
    * Accesses the type of the nearest enclosing top level block.
    *
    * @param   wa
    *          The current context's data or {@code null} to force a lookup of the context data.
    *
    * @return  The type of the enclosing top level block or {@code null} if there is no top-level
    *          block in the call stack.
    */
   private static BlockType topLevelType(WorkArea wa)
   {
      if (wa == null)
      {
         wa = work.obtain();
      }
      
      return wa.topType.peek();
   }

   /**
    * Check if we are on the top level of a persistent trigger.
    *
    * @param  wa
    *         The current context's data.
    *
    * @return <code>true</code> if we are on the top level of a persistent trigger
    */
   private static boolean isPersistentTriggerTopLevel(WorkArea wa)
   {
      // The top level of a persistent trigger has the following top-level blocks stack:
      // EXTERNAL_PROC/INTERNAL_PROC and then persistent TRIGGER.

      Iterator<BlockType> iter = wa.topType.iterator();
      if (!iter.hasNext())
      {
         return false;
      }

      BlockType top = iter.next();
      if (top != BlockType.EXTERNAL_PROC &&
          top != BlockType.INTERNAL_PROC)
      {
         return false;
      }

      if (!iter.hasNext() || iter.next() != BlockType.TRIGGER)
      {
         return false;
      }

      return LogicalTerminal.isTopTriggerPersistent();
   }
   
   /**
    * Update block execution statistics for the given block instance. Depending
    * of the block type, either the class name of the block will be inspected
    * or the call stack will be inspected to determine the block name and then
    * the usage statistics for that block will be incremented.
    *
    * @param    type
    *           The type of the block.
    * @param    block
    *           The block that is about to be executed.
    * @param    start
    *           The start time of the block's execution.
    */
   private static void recordExecutionStats(BlockType type, Block block, long start)
   {
      long end = System.currentTimeMillis();
      
      // the first application entry in the stack is the one that describes
      // what we are executing
      character sname = EnvironmentOps.getSourceName(1);
      
      String descr = null;
      
      // this shouldn't be null, but we will be safe anyway
      if (sname == null)
      {
         descr = "Unknown (call stack analysis failed)";
      }
      else
      {
         descr = sname.toStringMessage();
      }
      
      // triggers will appear as the same as an external procedure
      if (type == BlockType.TRIGGER ||
          type == BlockType.DATABASETRIGGER)
      {
         // calculate the specific trigger that was executed
         String className = block.getClass().getName();
         
         int idx = className.lastIndexOf('$');
         
         if (idx >= 0)
         {
            className = className.substring(idx + 1);
         }
         
         // append the trigger portion of the class name to the description
         descr = descr + ' ' + className;
      }
      
      // update the statistics
      AtomicInteger count = stats.get(descr);
      AtomicLong time = times.get(descr);
      if (count == null)
      {
         stats.put(descr, count = new AtomicInteger(0));
         times.put(descr, time = new AtomicLong(0));
      }
      time.addAndGet(end - start);
      count.incrementAndGet();
   }
   
   /**
    * The CATCH statement.  This API must be called from the Block's init method, and it will
    * register a listener for the specified STOP/ERROR condition.
    * <p>
    * The catch order is the order of this API registration calls.
    * 
    * @param    type
    *           The CATCH's error type.
    * @param    catchBlock
    *           The code to be executed for this error.
    */
   private static <T extends _BaseObject_> void registerCatchBlock(Class<T>            type,
                                                                   Consumer<object<T>> catchBlock)
   {
      BlockDefinition block = TransactionManager.getBlock();
      
      if (block.catchBlocks == null)
      {
         block.catchBlocks = new LinkedHashMap<>();
      }
      
      // check if any of the current caught types are a super-class or the same as the current 
      // type; if so, abort
      for (Class<?> cls : block.catchBlocks.keySet())
      {
         if (cls.isAssignableFrom(type))
         {
            return;
         }
      }
      
      block.catchBlocks.put(type, (Consumer) catchBlock);
   }
   
   /**
    * Generates a CSV file with the recorded execution statistics.
    */
   private static void dumpExecutionStats()
   {
      if (statsFile != null)
      {
         PrintWriter out = null;
         
         try
         {
            out = new PrintWriter(new File(statsFile));
         }
         
         catch (FileNotFoundException fnfe)
         {
            // TODO: log this?
         }
         
         if (out != null)
         {
            out.println("\"Entry Point\",\"Execution Counter\",\"Execution total time\"");
            
            Set<String>      keyset = stats.keySet();
            Iterator<String> keys   = keyset.iterator();
            
            while (keys.hasNext())
            {
               String  entry = keys.next();
               AtomicInteger count = stats.get(entry);
               AtomicLong time = times.get(entry);
               out.printf("\"%s\",\"%d\",\"%s\"\n", entry, count.get(), time.get());
            }
         
            out.flush();
            out.close();
         }
      }
   }
   
   /**
    * Helper to expose state in a way that avoids context local lookups.
    */
   static class BlockManagerHelper
   {
      /** The {@link WorkArea} instance. */
      private WorkArea wa;

      /**
       * Create a new instance and associate the given WorkArea instance.
       * 
       * @param    wa
       *           The {@link WorkArea} instance.
       */
      public BlockManagerHelper(WorkArea wa)
      {
         this.wa = wa;
      }
      
      /**
       * Mark the start of a pending dynamic call, via {@link ControlFlowOps}.
       */
      public void markPendingDynCall()
      {
         wa.pendingDynCall = true;
      }
   }
   
   /**
    * Stores global data relating to the state of the current context's
    * blocks.
    */
   private static class WorkArea
   {
      /** Helper to use the TM without any context local lookups. */
      public TransactionManager.TransactionHelper tm = TransactionManager.getTransactionHelper();
      
      /** Helper to use the ProcedureManager without any context local lookups. */
      public ProcedureManager.ProcedureHelper pm = ProcedureManager.getProcedureHelper();

      /** Helper to use the ControlFlowOps without any context local lookups. */
      public ControlFlowOps.ControlFlowOpsHelper cfops = ControlFlowOps.getHelper();
      
      /** Helper to use the ObjectOps without any context local lookups. */
      public ObjectOps.ObjectHelper objHelper = ObjectOps.getObjectHelper();
      
      /** Helper to use the ErrorManager without any context local lookups. */
      public ErrorManager.ErrorHelper errHelper = ErrorManager.getErrorHelper();
      
      /** A return value for each function block on the call stack. */
      public Deque<Object> funcRet = new ArrayDeque<>();
      
      /** Return processing type for the current function block on the call stack. */
      public ReturnType rtype = null;
      
      /** Tracks the type of each top-level block as a stack. */
      public ArrayDeque<BlockType> topType = new ArrayDeque<BlockType>();
      
      /** Common, long-lived instance to make leave processing faster. */
      public LeaveUnwindException leaveExc = new LeaveUnwindException();
      
      /** Common, long-lived instance to make next processing faster. */
      public NextUnwindException nextExc = new NextUnwindException();
      
      /** Common, long-lived instance to make return processing faster. */
      public ReturnUnwindException retExc = new ReturnUnwindException();
      
      /** Object responsible for managing stop-after on Progress blocks. */
      public StopAfterTimer stopAfterTimer = null;
      
      /** Block name which should be left. */
      public String deferredLeave = null;
      
      /** Block name which should be iterated. */
      public String deferredNext = null;
      
      /** Flag indicating if a proc/function is executed via ControlFlowOps.invoke APIs. */
      public boolean pendingDynCall = false;
      
      /** Flag indicating if stop-after is enabled in directory */
      public boolean isStopAfterActive = true;
      
      /** A code to execute instead of the next top-level block, as the argument assignment failed. */
      public Runnable ignoreNextCall = null;
      
      /** Parameter indicating whether Stop condition should be raised as OO error. */
      public int catchStopParameter = SessionUtils._startupParameters().getCatchStop() != null ? 
                                      SessionUtils._startupParameters().getCatchStop() :
                                      0;
   }
   
   /**
    * Simple container that stores and returns a context-local instance of
    * the global work area.
    */
   private static class ContextContainer
   extends ContextLocal<WorkArea>
   {
      /**
       * Obtains the context-local instance of the contained global work
       * area.
       *
       * @return   The work area associated with this context.
       */
      public WorkArea obtain() 
      {
         return this.get();
      }   
      
      /**
       * Initializes the work area, the first time it is requested within a
       * new context.
       *
       * @return   The newly instantiated work area.
       */
      protected synchronized WorkArea initialValue()
      {
         boolean stopAfter = Utils.getDirectoryNodeBoolean(null, 
                                                           "legacy-system/stop-after", 
                                                           true, 
                                                           Utils.DirScope.BOTH, 
                                                           null);
         WorkArea wa = new WorkArea();
         
         if (!stopAfter)
         {
            wa.isStopAfterActive = false;
         }
         
         return wa;
      }   
   }
   
   /**
    * Server-wide hook that gets called at initialization and termination. We
    * use this to write out execution statistics when the statistics counters
    * are enabled.
    */
   private static class StatsHelper
   implements InitTermListener
   {
      /**
       * This method is invoked when server is about to be started.
       */
      public void initialize()
      {
         // do nothing
      }
   
      /**
       * This method is invoked when the server is terminating.
       * 
       * @param    t
       *           Error or exception which caused exit of the server. Can
       *           be <code>null</code> if there was a normal end.
       */
      public void terminate(Throwable t)
      {
         dumpExecutionStats();
      }
   }
}