QueryWrapper.java

/*
** Module   : QueryWrapper.java
** Abstract : Proxy for concrete query implementations
**
** Copyright (c) 2005-2025, Golden Code Development Corporation.
**
** -#- -I- --Date-- --JPRM-- -----------------------------------Description-----------------------------------
** 001 ECF 20060430   @25885 Created initial version. Merged contents of
**                           AbstractQueryWrapper, CompoundQueryWrapper,
**                           PreselectQueryWrapper, and RandomAccessQuery-
**                           Wrapper. These classes are now obsolete. The
**                           merge was required because the same define
**                           query statement in Progress can be followed
**                           by many open query statements for that query;
**                           however, each open query may open a query of
**                           a different type than the previous one. Thus,
**                           a single wrapper type which supports all
**                           query types as delegates is required.
** 002 ECF 20060504   @25970 Added safety code. A default delegate query
**                           is automatically assigned upon construction,
**                           which has safe implementations of P2JQuery
**                           methods.
** 003 ECF 20060618   @27423 Change to assign() methods. Ensure query is
**                           set to scrolling upon assignment if the
**                           scrolling flag was previously set.
** 004 ECF 20061023   @30608 Added errorIfNull logic. P2JQuery interface
**                           now requires an implementation of the
**                           setErrorIfNull() method. The value set by the
**                           caller of this method is set into the query
**                           delegate, if one exists. If a delegate has
**                           not yet been assigned to the wrapper, the
**                           setting of this state in the delegate is
**                           deferred until a delegate is assigned.
** 005 ECF 20061027   @30754 Replaced Object with DataModelObject for DMO
**                           arguments to methods/constructors. Required
**                           for compile-time type safety.
** 006 ECF 20061102   @30960 Added support for reposition notification and
**                           auto-fetch features.
** 007 ECF 20061204   @31577 Implemented new P2JQuery methods to support
**                           browse.
** 008 NVS 20070502   @33345 Assigning a query should notify all listeners
**                           so that the related browse widget gets the
**                           notification and refreshes the display.
** 009 SIY 20070502   @33429 Added notifyRepositionListeners() method.
**                           Changed assignImpl() to use this new method.
**                           Minor cleanups in docs.
** 010 ECF 20070716   @34508 Added cleanup infrastructure. Wrapper is
**                           registered with TM at construction. At end of
**                           scope, cleanup is delegated to wrapped query.
**                           This ensures delegate does not clean up too
**                           early, since delegate may be assigned at a
**                           more deeply nested scope than those at which
**                           the wrapper can be used.
** 011 SIY 20070726   @34706 Helper method for explicit notification 
**                           invocations.
** 012 ECF 20080202   @37005 Changed constructor signature. Added argument
**                           to indicate whether delegate query is a
**                           scrolling query. This allows us to avoid an
**                           ugly, anonymous initializer in converted code
**                           which does nothing more than invoke the
**                           setScrolling() method. Also, automatically
**                           invoked delegate's open() method when a
**                           PreselectQuery delegate is assigned.
** 013 ECF 20080509   @38244 Fixed assignImpl(). Removed notification to
**                           reposition listeners. This is handled from
**                           the delegate's open() method, which is now
**                           part of P2JQuery and is called when the
**                           delegate is assigned.
** 014 ECF 20080509   @38253 Fixed regression introduced by #013 (@38244).
**                           assignImpl() must not call open() for a
**                           multi-table query, since this will trigger
**                           execution of the query too early. Deprecated
**                           notifyListeners(), which should be replaced
**                           in business logic with open().
** 015 ECF 20080512   @38495 Changed setScrolling(). Do not process method
**                           body more than once.
** 016 SVL 20080604   @38533 Modified according to the new P2JQuery
**                           interface.
** 017 ECF 20080729   @39327 Added rowid support. Refactored reposition*()
**                           methods.
** 018 ECF 20081106   @40325 Added _isOffEnd(). Required by P2JQuery
**                           interface change.
** 019 CA  20081210   @40840 Implemented CLOSE QUERY statement. On close,
**                           it must notify all browse widgets to reset 
**                           their state.
** 020 CA  20081211   @40860 Fixed regression introduced by H019: the 
**                           delegate needs to be explicitly closed, not
**                           cleaned.
** 021 CA  20090227   @41389 Added WrappedResources.isUnknown method; this
**                           implementation returns false.
** 022 SIY 20090306   @41425 Close delegate if new one is assigned. This is
**                           necessary to properly notify underlying browse
**                           when they are associated with query.
** 023 ECF 20090312   @42981 Implemented getTableCount(). Supports NUM-BUFFERS
**                           query handle attribute. Changed some integer
**                           parameters to recids. Use parameterized form of
**                           WeakList.
** 024 SVL 20090730   @43446 Removed open() call from assign(). It should be
**                           called externally.
** 025 CA  20090731   @43469 Register the query for off-end listener 
**                           registration after block initialization (done
**                           only for block types FOR and FOR EACH). Added
**                           getOffEndListeners, which returns a list of all
**                           off-end listeners for all used buffers.
** 026 SVL 20091030   @44289 Added getOffEnd() function to QueryWrapper and
**                           DefaultDelegate in order to support API change
**                           into P2JQuery.
** 027 SVL 20111111          presortDelegate checks that delegate is an
**                           instance of PresortDelegate (rather than
**                           PresortQuery).
** 028 VMN 20130207          Added support for handle-based methods:
**                           GET-BUFFER-HANDLE (KW_GET_BUFH)
**                           GET-CURRENT (KW_GET_CUR),
**                           QUERY-CLOSE (KW_QRY_CLOS),
**                           REPOSITION-FORWARD (KW_REPOS_F),
**                           REPOSITION-TO-ROW (KW_REPOS_2R)
**                           REPOSITION-TO-ROWID (KW_REPOS_2I),
**                           and attributes
**                           NUM-RESULTS (KW_NUM_RES)
**                           and attributes
**                           NUM-RESULTS (KW_NUM_RES)
** 029 OM  20130212          Added implementation stubs for some dynamic methods.
** 030 VMN 20130213          Added support for attributes
**                           INDEX-INFORMATION (KW_IDX_INFO)
**                           FORWARD-ONLY (KW_FWD_ONLY)
**                           PREPARE_STRING (KW_PREP_STR)
** 031 VMN 20130219          Added support for attributes
**                           IS-OPEN (KW_IS_OPEN)
** 032 CA  20130221          Added ADM-DATA, UNIQUE-ID and chaining support.
** 033 OM  20130304          Refactored isValid and isUnknown of WrappedResource to valid 
**                           and unknown.
** 034 VMN 20130306          Added addBuffer(handle bufHandle) and corrected support
**                           for handle-based methods:
**                           GET-NEXT (KW_GET_NEXT)
**                           GET-PREV (KW_GET_PREV)
**                           GET-FIRST (KW_GET_1ST)
**                           GET-LAST (KW_GET_LAST)
**                           GET-CURRENT (KW_GET_CUR)
**                           Implemented
**                           getFirst(),getNext(),getLast(),getPrevious(),getCurrent()
** 035 CA  20130311          Added bufferHandle(integer).
** 036 VMN 20130311          Implemented queryClose, queryForward,
**                           queryReposition, queryRepositionByID,
**                           Delegating methods
** 037 VMN 20130312          Corrected conversion and runtime for
**                           REPOSITION-TO-ROW (KW_REPOS_2R)
** 038 CA  20130315          Added missing INDEX-INFORMATION API.
** 039 OM  20130320          Added implementation for ResultListHandler interface.
** 040 VMN 20130321          Corrected conversion and runtime for
**                           NUM-BUFFERS attribute(KW_NUM_BUFF)
** 041 CA  20130322          Added missing queryForward(integer) API.
** 042 SVL 20130325          Added include and exclude functions.
** 043 CA  20130603          resourceDelete must return a boolean value.
** 044 CA  20130927          Removed unknown() API, as by default the resource is known. 
** 045 ECF 20130405          Moved createQuery static methods here from AbstractQuery.
**                           Cleaned up some documentation.
** 046 CA  20131024          Implemented runtime for the QUERY resource (static or dynamic). 
** 047 ECF 20131028          Import change.
** 048 SVL 20131203          Changes caused by renaming of Nameable.get/setName to Nameable.name.
** 049 CA  20131123          Removed some interfaces which are implemented by HandleChain.  Query
**                           cleanup must be performed only when the query gets explicitly or
**                           implicitly deleted.
** 050 SVL 20140430          Close the query when the external [persistent] procedure in which the
**                           query was opened is deleted. Call assignImpl() in prepare().
** 051 SVL 20140604          Added support for INDEX-INFORMATION.
** 052 SVL 20140909          Added isNativelyPreselect. Fixed reset of fetchOnReposition.
** 053 ECF 20141124          Added queryBackward methods.
** 054 OM  20150205          Queries do not need to be unregistered from DynamicQueryHelper.
** 055 SVL 20150218          Set fetchOnReposition to true for browsed queries on query
**                           reassignment.
** 056 SVL 20150305          Add buffers to the buffers array in order to make bufferHandle
**                           work properly. Consider query "is not open" if it is closing.
**                           Use force handle assignment in bufferHandle (ignoring pending
**                           errors).
** 057 SVL 20150331          Added deleteResultListEntry(boolean).
** 058 SVL 20150722          Updated notifyRepositionListeners signature.
** 059 ECF 20150801          Added setIterationType variant and optimize method.
** 060 SVL 20150821          Added isScrolling, removeRepositionListener, isBrowsed, getName.
** 061 OM  20150915          Added stub for SKIP-DELETED-RECORD attribute.
** 062 OM  20151029          Added minimal runtime support for SKIP-DELETED-RECORD attribute.
** 063 SVL 20151118          Static queries are registered at the procedure in which they were
**                           defined. Dynamic queries are closed when the scope of an underlying
**                           buffer ends.
** 064 ECF 20160106          Fixed close method to not reset to the default delegate, since the
**                           query can be re-opened and used again.
** 065 EVL 20160217          Clean up comments from symbols invalid for Solaris to compile.
** 066 SVL 20160314          Added setParameterFilter.
** 067 SVL 20160721          Set fetchOnReposition for browsed queries in open() too (for query
**                           reopen case).
** 068 ECF 20160725          Added setExternalBuffers method and new P2JQuery methods.
** 069 GES 20160804          Switched from WhereExpression to lambda usage.
** 070 CA  20161012          Fixed scope processing when the query is from a persistent 
**                           procedure, and is part of a QUERY resource.
** 071 SVL 20161108          Do not open query on PREPARE.
** 072 HC  20170127          Fixed REPOSITION-FORWARD and REPOSITION-BACKWARD to return the
**                           value based on whether the new cursor position is "off-end".
**     SVL 20170126          Added bufferHandle(), changed signature of
**                           queryForward/queryBackward.
**     OM  20170209          Added return value for repositioning methods.
** 073 ECF 20171002          getNumResults returns unknown value if not scrolling.
** 074 GES 20171207          Removed forced version of assign().
** 075 OM  20171129          releaseBuffers() is implemented from P2JQuery.
** 076 ECF 20180201          Removed optimize method.
** 077 OM  20180515          Added dynamic filters and dynamic sort.
** 078 SVL 20180901          Refactored dynamic sorting functions.
**     OM  20180924          Filtering on decimal fields uses STRING(f, format) function.
** 079 OM  20181010          Clearing dynamic sorting failed when no sorting was active.
** 080 ECF 20181106          Added runtime support for {FIRST|LAST}-OF methods.
** 081 OM  20181206          Added QUERY readonly attribute for BUFFERs. Added support for dynamic
**                           evaluations.
**     CA  20181220          Added REPOSITION-TO-ROWID(character) stub.
** 082 ECF 20190302          Renamed setExternalBuffers to addExternalBuffers and changed
**                           implementation, since it may be called multiple times on a query.
** 083 OM  20190228          Removed deleted buffers from dynamic queries.
** 084 SVL 20190320          Updated createResultListEntry.
** 085 OM  20190327          Renamed DataSource to avoid conflicts with DataSet source.
** 086 OM  20190611          Added support for substitution buffers for dynamic queries.
** 087 OM  20190720          Added repositionByID() for internal usage.
**     CA  20190812          Changes to allow for mutable buffers; any API which receives a Buffer 
**                           instance and is invoked from converted code must resolve the runtime
**                           instance before saving the instance.
**     HC  20190823          When query is deleted it must be unassigned from browse.
**     EVL 20190823          Fix for query reposition with dynamic browse too early query set.
**     CA  20190913          REPOSITION must raise an ERROR condition if the query is not opened.
** 088 SVL 20191002          Suppress query off-end exception for all wrapped navigation
**                           statements like "q:get-next()" or "get next q".
**                           If the query is bound to a browse, then the
**                           query:CREATE/DELETE-RESULT-LIST-ENTRY calls are redirected to
**                           browse:CREATE/DELETE-RESULT-LIST-ENTRY.
** 089 CA  20191005          A query must know if it is dynamic, when closing.
** 090 SVL 20191114          Fixed undesirable release of buffers for browsed preselect queries.
**     CA  20200110          A small improvement in resourceDelete.
** 091 RFB 20200312          Added asHandle() method for handling QUERY q:HANDLE
**     CA  20200428          QUERY handle has all callback-procedure APIs.
**     CA  20200503          Added QUERY:CACHE runtime stub.
** 092 ECF 20200906          New ORM implementation.
** 093 CA  20200624          Static query resources can have their underlying query delegate changed via 
**                           QUERY-PREPARE.
**     CA  20200918          INDEX-INFORMATION requires to interpret the 'execute' method for a dynamic query
**                           without evaluating the dynamic calls in the WHERE.
**                           Fixed multiple QUERY-OPEN() calls - must close the query before reopening.
**     VVT 20210108          repositionByID() fixed to match 4gl behaviour: see #5038-39
**     OM  20201120          Added OFF-END callback.
**     OM  20210219          bufferHandle() accepts int64 expression parameters.
**     CA  20210310          A dynamic predicate must set the default lock to NONE, instead of SHARE.
**     SVL 20210413          Added query wrapper listeners. Do not create a new delegate for dynamically
**                           sorted compound queries.
**     AIL 20210505          Implemented setBuffers(Object...).
**     AIL 20210507          Added support for addBuffer(character) and addBuffer(String).
**     ECF 20210511          Replaced DynamicTablesHelper.normalizeName with TextOps.rightTrimLower.
**     CA  20210516          Implemented getRecordBuffers().
**     CA  20210527          isOffEnd() will return unknown for any closed query, regardless if static or
**                           dynamic.
**     ECF 20210723          Changed signature of delegate query close worker method.
**     AL2 20210909          Added support for indexed reposition.
**     CA  20210920          When a buffer is deleted, all related queries must be reset (their predicate and
**                           buffer list).
**     CA  20210923          assign(CompoundQuery) must not reset the query.  Removed the 'closing' flag.
**     OM  20220112          Added implementation of SKIP-DELETED-RECORD attribute.
**     CA  20220930          Refactored the callback invocation to be performed via a call-site and 
**                           InvokeConfig, to allow caching of the resolved target.
**     CA  20221006          UNIQUE-ID and ADM-DATA are kept as Java types instead of BDT.  Refs #6827
**     TJD 20220504          Upgrade do Java 11 minor changes - added deprecated annotation
**     GES 20210501          Upgraded dataset parameter processing to match API changes.
**     CA  20220909          When a query gets deleted and is set at the query buffers' 'lastQuery', remove  
**                           the reference.
**     CA  20221123          Static QUERY instances must not be added to SESSION:FIRST-QUERY chain.
**     SVL 20230108          Improved performance by replacing some "for-each" loops with indexed "for" loops.
**     CA  20230110          UNIQUE-ID is generated only when is read by the application.
**                           Cache the helper for ProcedureManager, ObjectOps and others (as needed), to reduce  
**                           context-local lookup.
**     HC  20230116          Replaced some handle usages with the actual wrapped resources for
**                           performance.
**     SVL 20221215          Reflected API change for setQuery.
**     CA  20230116          Avoid using handle.unwrap, handle.getReference or other BDT usage from within FWD 
**                           runtime.
**     HC  20230118          Eliminated some of the uses of String.toUpperCase and/or
**                           String.toLowerCase for performance.
** 094 IAS 20230405          Fixed FILL support for recursive DATA-RELATION
** 095 AL2 20230411          Notify query close listeners.
** 096 GBB 20230512          Logging methods replaced by CentralLogger/ConversionStatus.
** 097 CA  20230724          Further reduce context-local usage.
** 098 AD  20231108          Fixed inverse assignment of skipDeletedRecordDisposition in constructor.
** 099 ES  20231203          Added new setLenientOffEnd method.
**     ES  20231212          Removed handleQueryOffEnd method and all of its usage.
**                           Set lenientOffEnd for for PreselectQuery and CompundQuery.
** 100 OM  20231004          Handling errors in QUERY-OPEN implementation instead of propagating the error.
**     OM  20240110          Implicit queries cannot be deleted using delete object statements.
** 101 AL2 20240307          Mark the query to retrieve the entire result set (useful for FILL operations).
** 102 CA  20240320          Avoid BDTs within internal FWD runtime.  Replaced iterators with Java 'for',  
**                           where it applies.
** 103 CA  20240324          Use logical constants for TRUE, FALSE, UNKNOWN, within internal FWD runtime.
** 104 OM  20240401          The setSubstitutionBuffers() method used for configuring the substitution buffers
**                           of a dataset buffer now contains the code for collecting them.
** 105 ES  20240404          Overridden setIteration, isIteration, setPresort and isPresort methods.
** 106 CA  20240424          The buffer to which a DATA-SOURCE is attached needs to be available to the FILL 
**                           query. 
** 107 CA  20240422          Allow the query to be reset to its initialization state, so the same instance can
**                           be used to execute child buffer FILL operations.
** 108 DDF 20240527          Swapped call to recordOrShowError() with recordOrShowDatabaseError().
**     DDF 20240528          Replaced recordOrShowError() in indexInformation().
** 109 CA  20240809          Avoid iterator usage, for performance improvement.
** 110 CA  20240918          Removed default methods from interfaces and moved them as concrete implementations,
**                           as default methods cause the Java metaspace to spike one order of magnitude.
** 111 DDF 20230711          Allow reposition only when the query is non-scrolling.
**     DDF 20230712          Added setForwardOnly() method and originalScrolling property.
**     DDF 20230713          Handle errors for setting the FORWARD-ONLY attribute on a query that is being
**                           browsed.
**     DDF 20230717          Properly propagate scrolling in delegates.
**     DDF 20230721          Fixed forwardOnly assignment in delegates. Scrolling should be propagated
**                           only once in delegate and replace originalScrolling usage.
**     DDF 20230823          Errors should be thrown for dynamic queries and shown for static queries.
**     DDF 20241021          Removed unnecessary boolean parameter and replaced recordOrShowDatabaseError()
**                           with recordOrShowError() where the error handling is different for static and
**                           dynamic queries.
** 112 OM  20241128          Multi-tenant runtime support: selected the proper persistence context, eventually
**                           based on [sharedDb] parameter.
**                           Implementation of [setMultiTenantAlternative] method.
** 113 AL2 20241205          Re-delegate from AdaptiveQuery to PreselectQuery when adding dynamic sorts.
** 114 CA  20250321          Added 'setCallback' overloads.
** 115 AL2 20250416          Added support for "forceDatabaseJoin".
** 116 CA  20250422          Added support for REPOSITION-BY-ID(rowid[]), where the arg is an extent.
*/

/*
** 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.persist;

import java.util.*;
import java.util.function.*;
import java.util.logging.*;
import com.goldencode.p2j.persist.event.*;
import com.goldencode.p2j.persist.lock.*;
import com.goldencode.p2j.util.*;
import com.goldencode.p2j.util.ErrorManager;
import com.goldencode.p2j.util.UniqueIdGenerator.IdKind;
import com.goldencode.p2j.util.logging.*;

/**
 * A delegating container implementation for {@link AbstractQuery}s.  An
 * instance of this class contains an instance of <code>AbstractQuery</code>,
 * to which it delegates the work of all of its methods.
 * <p>
 * The purpose of this class is to support queries defined in Progress using
 * the DEFINE QUERY statement.  These may be defined once, but opened and
 * closed multiple times.  In the P2J implementation, a new instance of
 * <code>AbstractQuery</code> is constructed each time a query is "opened"
 * (i.e., an OPEN QUERY was issued in the pre-conversion code).  Since a
 * reference to the query may be held by many routines, the query's internal
 * state must be updated when the query is opened or re-opened.  This is
 * accomplished by sharing a reference to an instance of this class, which
 * always holds the most recently constructed, underlying query.  Thus, since
 * all routines are accessing the query via this container (i.e., essentially
 * by proxy), they will always be accessing the correct, underlying query.
 * When a new query is opened, the new <code>AbstractQuery</code> instance is
 * stored in the wrapper via one of the <code>assign</code> method variants.
 * <p>
 * The public methods of this class may only be invoked if the underlying
 * delegate query is of a type which implements a method of the same
 * signature.  Many methods are supported by {@link AbstractQuery}, which is
 * the abstract base class of all concrete query implementations.  However,
 * certain methods are implemented only by particular implementations.  These
 * will fail with an <code>IllegalStateException</code> if invoked when the
 * wrong type of delegate has been set.
 * <p>
 * When an instance of this class is first created, a no-op, default
 * implementation of <code>P2JQuery</code> is assigned immediately.  This
 * ensures that at least those methods which are defined by the
 * <code>P2JQuery</code> interface have a safe methods.  However, this does
 * not protect the caller from invoking methods which are unique to specific
 * query types, if no safe delegate has first been assigned.  This safety
 * measure is intended to protect other runtime code which generically uses
 * an instance of this class via the <code>P2JQuery</code> interface (such as
 * <code>BrowseWidge</code> in the UI).
 * <p>
 * A query wrapped by this object may need to clean up resources when the
 * wrapper goes out of scope.  A cleaner object is registered with the
 * transaction manager upon construction of the wrapper, at the next external
 * scope.  This scope assumes that a <code>QueryWrapper</code> is only
 * instantiated as an instance member of a business logic class.  This is the
 * case for all converted Progress code.
 */
@LegacyResource(resource = LegacyResource.QUERY)
public final class QueryWrapper
extends HandleChain
implements P2JQuery,
           ADMData,
           UniqueID,
           DynamicResource,
           ResultListHandler,
           CallbackProcedure
{
   /** Logger */
   private static final CentralLogger LOG = CentralLogger.get(QueryWrapper.class.getName());
   
   /** Default delegate to use before a real one is assigned */
   private static final P2JQuery DEFAULT_DELEGATE = new DefaultDelegate();
   
   /** The {@code OFF-END} event string constant in upper case. */
   private static final String OFF_END_EVENT = "OFF-END";
   
   /** The call-site for the {@link #OFF_END_EVENT} event callback. */
   private static final InvokeConfig OFF_END_CALL_SITE = new InvokeConfig();
   
   /** Delegate query */
   private P2JQuery delegate = null;
   
   /** Original query type before any dynamic operations. */
   private Class<? extends P2JQuery> originalQueryType = null;
   
   /** Reposition listeners registered with the delegate query */
   private final WeakList<RepositionListener> repoListeners = new WeakList<>();
   
   /** Should delegate be a scrolling query? */
   private boolean scrolling = false;
   
   /** Should delegate be optimized using indexed reposition */
   private boolean indexedReposition = false;
   
   /** Should delegate's failed first/last/unique retrievals raise error? */
   private boolean errorIfNull = true;
   
   /** Should the next row of the delegate be fetched after a reposition? */
   private boolean fetchOnReposition = false;
   
   /** Is query associated with a UI browse widget? */
   private boolean browsed = false;
   
   /** Opened listeners registered to get the message about query has been opened. */
   private final ArrayList<QueryOpenedListener> openedListeners = new ArrayList<>();

   /** Query wrapper listeners. */
   private Set<QueryWrapperListener> wrapperListeners;
   
   /** Flag indicating if the query was explicitly closed or is not open. */
   private boolean closed = true;
   
   /** Current off-end state. Used to detect when off-end state was encountered and fire OFF-END callback. */
   private boolean offEnd = false;
   
   /** Flag indicating if the query has been advanced (via GET NEXT) to the next record. */
   private boolean advanced = false;
   
   /** Flag indicating if this query is dynamic. */
   private boolean dynamic = false;
   
   /** Enforce a database join when the optimizer will kick in. */
   private boolean forceDatabaseJoin = false;
   
   /**
    * Flag indicating if the query's {@link #delegate} is dynamic. This can be true even for a static query 
    * resource. 
    */
   private boolean dynamicDelegate = false;
   
   /** Corresponds ADM-DATA attribute. */
   private String admData;
   
   /** Corresponds UNIQUE-ID attribute. */
   private Long uniqueID = null;
   
   /** Corresponds FORWARD-ONLY attribute. */
   private boolean forwardOnly = false;
   
   /** Contains the prepare string set by {@link #prepare}. */
   private String prepareString = null;
   
   /** The set of buffers used by this dynamic query. */
   private final ArrayList<Buffer> buffers = new ArrayList<>();
   
   /** Check if this query is valid. */
   private boolean valid = true;
   
   /** Internal reference for the query's name. */
   private final String qname;
   
   /** If the cleaner is already registered as a finalizable for this wrapper. */
   private boolean cleanerRegistered = false;
   
   /**
    * The initial disposition for the value of SKIP-DELETED-RECORD. It is {@code true} for normal queries and
    * {@code false} for static browsed queries.
    */
   private boolean skipDeletedRecordDisposition = true;
   
   /**
    * The list of substitution buffers. These are not the main buffers the query is iterating but
    * may appear in SUBST nodes (as substitution). By default (when {@code null}), each buffer in a
    * dynamic query must appear exactly one time in FOR clause. 
    */
   private List<Buffer> substBuffers = null;
   
   /** External handler for create/delete result list entry methods. */
   private ResultListHandler externalResultListHandler = null;
   
   /** The only possible callback. {@code null} if not set.*/
   private  CallbackData callback = null;
   
   /** The recursive DATA-RELATION the query is to FILL for */
   private DataRelation relation = null;
   
   /**
    * Flags this query as an explicit query to allow the programmer to delete it. When a query is created
    * implicitly, the programmer will not be able to delete it (err 12349), but the deletion of the object is
    * performed automatically.
    */
   private boolean explicit = true;
   
   /**
    * Constructor which creates a static query and sets query scrolling mode for all delegate 
    * queries assigned to this wrapper.
    *
    * @param   name
    *          The legacy name of this query.
    * @param   scrolling
    *          {@code true} to set all delegate queries assigned to this wrapper to scrolling mode,
    *          else {@code false} to not use scrolling mode.
    *
    * @deprecated This method was kept only to make the code already compiled against previous revision of FWD
    *             work. Although the code is unchanged the runtime will attempt to use of this signature as
    *             chosen by linker instead of {@code QueryWrapper(String, boolean, String...)}.
    */
   @Deprecated
   public QueryWrapper(String name, boolean scrolling)
   {
      this(name, scrolling, new String[] {});
   }
   
   /**
    * Constructor which creates a static query and sets query scrolling mode for all delegate 
    * queries assigned to this wrapper.
    * 
    * @param   name
    *          The legacy name of this query.
    * @param   scrolling
    *          {@code true} to set all delegate queries assigned to this wrapper to scrolling mode,
    *          else {@code false} to not use scrolling mode.
    * @param   browseNames
    *          The legacy name of any BROWSEs widgets which use this query.
    */
   public QueryWrapper(String name, boolean scrolling, String... browseNames)
   {
      this(name, scrolling, false);
      int brCount = browseNames.length;
      skipDeletedRecordDisposition = brCount == 0;
      if (brCount > 1)
      {
         for (int k = 0; k < brCount - 1; k++)
         {
            ErrorManager.recordOrShowError(3147, name, "");
            // Cannot browse query <query> because query is already being browsed. (3147)
         }
      }
   }
   
   /**
    * Constructor which sets query scrolling mode for all delegate queries assigned to this 
    * wrapper.
    * 
    * @param   name
    *          The legacy name of this query.
    * @param   scrolling
    *          <code>true</code> to set all delegate queries assigned to this wrapper to scrolling
    *          mode, else <code>false</code> to not use scrolling mode.
    * @param   dynamic
    *          Flag identifying a dynamic query.
    */
   private QueryWrapper(String name, boolean scrolling, boolean dynamic)
   {
      super(dynamic, dynamic);
      
      this.name = name;
      this.qname = name;
      this.dynamic = dynamic;
      
      // Store a safe delegate until a real one is assigned.
      this.delegate = DEFAULT_DELEGATE;
      
      if (scrolling)
      {
         setScrolling();
      }
      
      TransactionManager.registerOffEndQuery(this);
   }

   /**
    * Clear the current results from the query, so the same query instance can be executed again, without 
    * having to {@link #open() re-open} it.
    */
   @Override
   public void clearResults()
   {
      if (delegate != null)
      {
         delegate.clearResults();
      }
   }
   
   /**
    * Mark the query to retrieve the entire result set (useful for FILL operations).
    */
   public void hintFullResults()
   {
      if (delegate != null)
      {
         delegate.hintFullResults();
      }
   }
   
   /**
    * Register the cleaner which closes the query when the external [persistent] procedure in
    * which the query was opened is deleted.
    */
   private void registerCleaner()
   {
      Finalizable cleaner = new Finalizable()
      {
         @Override
         public void finished()
         {
         }
         
         @Override
         public void deleted()
         {
            if (!closed)
            {
               close();
            }
         }
         
         @Override
         public void iterate()
         {
         }
         
         @Override
         public void retry()
         {
         }
      };
      TransactionManager.registerTopLevelFinalizable(cleaner, true);
      
      cleanerRegistered = true;
   }
   
   /**
    * Dynamically creates a query in the specified widget pool and assign 
    * it to a handle. 
    * This method is the equivalent of <code>CREATE QUERY</code> from 4GL.
    * 
    * @param   hQuery
    *          The handle to assign the newly created query.
    * @param   widgetPool
    *          The name of the widget pool that contains the dynamic query. <code>null</code> if
    *          the unnamed pool must be used.
    */
   public static void createQuery(handle hQuery, String widgetPool)
   {
      createQuery(hQuery, (widgetPool == null ? null : new character(widgetPool)));
   }
   
   /**
    * Dynamically creates a query in the specified widget pool and assign 
    * it to a handle. 
    * This method is the equivalent of <code>CREATE QUERY</code> from 4GL.
    * 
    * @param   hQuery
    *          The handle to assign the newly created query.
    * @param   widgetPool
    *          The name of the widget pool that contains the dynamic query. <code>null</code> if
    *          the unnamed pool must be used.
    */
   public static void createQuery(handle hQuery, character widgetPool)
   {
      // validate widget pool before anything else!!!
      if (!WidgetPool.validWidgetPool(widgetPool))
      {
         return;
      }
      
      // create the query; use an empty string as its name
      QueryWrapper res = new QueryWrapper("", true, true);
      hQuery.assign(res);

      res.addToPool(widgetPool);
   }
   
   /**
    * Dynamically creates a query and assign it to a handle. This form of the 
    * method will create the object in the current default widget pool.
    * This method is the equivalent of <code>CREATE QUERY</code> from 4GL. 
    * 
    * @param   hQuery
    *          The handle to assign the newly created query.
    */
   public static void createQuery(handle hQuery)
   {
      createQuery(hQuery, (character) null);
   }

   /**
    * Dynamically creates a query in the specified widget pool.
    *
    * This method is the equivalent of <code>CREATE QUERY</code> from 4GL.
    *
    * @return  the newly created query.
    */
   public static QueryWrapper createQueryUnnamedPool()
   {
      // create the query; use an empty string as its name
      QueryWrapper res = new QueryWrapper("", true, true);
      res.addToPool(null);
      return res;
   }
   
   /**
    * Conversion of DYNAMIC attribute. Returns <code>true</code> if the buffer is dynamic.
    *
    * @return   <code>true</code> if the resource is dynamic, <code>false</code> otherwise. 
    */
   @Override
   public logical dynamic()
   {
      return logical.of(dynamic);
   }

   /**
    * Conversion of DYNAMIC attribute. Returns <code>true</code> if the buffer is dynamic.
    *
    * @return   <code>true</code> if the resource is dynamic, <code>false</code> otherwise. 
    */
   @Override
   public boolean _dynamic()
   {
      return dynamic;
   }
   
   /**
    * Assign a newly opened <code>CompoundQuery</code> instance as this
    * container's active delegate query.
    *
    * @param   delegate
    *          New delegate query.
    */
   public void assign(CompoundQuery delegate)
   {
      // DO NOT RESET THE QUERY HERE!
      assignImpl(delegate);
      delegate.setLenientOffEnd(true);
   }
   
   /**
    * Assign a newly opened <code>PreselectQuery</code> instance as this
    * container's active delegate query.
    *
    * @param   delegate
    *          New delegate query.
    */
   public void assign(PreselectQuery delegate)
   {
      addBuffers(delegate, true);
      
      assignImpl(delegate);
      delegate.setLenientOffEnd(true);
   }
   
   /**
    * Assign a newly opened <code>RandomAccessQuery</code> instance as this
    * container's active delegate query.
    *
    * @param   delegate
    *          New delegate query.
    */
   public void assign(RandomAccessQuery delegate)
   {
      addBuffers(delegate, true);
      
      assignImpl(delegate);
      delegate.setLenientOffEnd(true);
   }
   
   /**
    * Ensure that any <code>AbstractQuery</code> assigned to this wrapper is
    * a scrolling query, to enable results list scrolling/repositioning.  If
    * a query is already assigned to this wrapper, invoke its
    * <code>setScrolling</code> method immediately.
    */
   public void setScrolling()
   {
      if (!scrolling)
      {
         scrolling = true;
         if (delegate != null)
         {
            getDelegate().setScrolling();
         }
      }
   }
   
   /**
    * Indicate whether this query was defined as SCROLLING.
    *
    * @return  <code>true</code> if this query is scrolling.
    */
   public boolean isScrolling()
   {
      return scrolling;
   }
   
   /**
    * Indicate whether the query is defined inside the scope of FOR EACH block.
    *
    * @param   iterating
    *          <code>true</code> indicating that a query is inside FOR EACH block;
    *          <code>false</code> is defined outside of a FOR EACH.
    */
   @Override
   public void setIterating(boolean iterating) 
   {
      delegate.setIterating(iterating);
   }

   /**
    * Indicate whether the delegate query is defined inside the scope of FOR EACH block.
    *
    * @return  <code>true</code> if the query was defined inside a FOR EACH block.
    */
   @Override
   public boolean isIterating() 
   {
      return delegate.isIterating();
   }

   /**
    * Indicate whether the delegate query is of presort type.
    *
    * @return  <code>true</code> if the query is of presort type..
    */
   @Override
   public boolean isPresort() 
   {
      return delegate.isPresort();
   }

   /**
    * Indicate whether the delegate query is of presort type.
    *
    * @param   presort
    *          <code>true</code> indicating that a query of presort type.
    *          <code>false</code> is not of presort type.
    */
   @Override
   public void setPresort(boolean presort) 
   {
      delegate.setPresort(presort);
   }
   
   /**
    * Enforce a database join if possible. By default, multi-table queries rely on 
    * algorithm to decide whether a database join is optimal or not. With such setter,
    * the database join is always preferred.
    * 
    * @param   forceDatabaseJoin
    *          {@code true} if the query should always use DB joins.
    */
   @Override
   public void setForceDatabaseJoin(logical forceDatabaseJoin)
   {
      this.forceDatabaseJoin = forceDatabaseJoin.booleanValue();
      if (delegate != null)
      {
         getDelegate().setForceDatabaseJoin(forceDatabaseJoin);
      }
   }
   
   /**
    * Check if the database join enforcing is active.
    * 
    * @return   {@code true} if the query will always use DB joins.
    */
   @Override
   public logical isForceDatabaseJoin()
   {
      return logical.of(this.forceDatabaseJoin);
   }
   
   /**
    * Ensure that any <code>AbstractQuery</code> assigned to this wrapper is
    * a optimized query using indexed reposition. This flag can be set only if
    * the query is scrolling. An indexed reposition query can be repositioned
    * to an unflushed record (one which was not in the database when the 
    * query was opened). Repositioning to such record will empty the result list.
    * 
    * @throws  ErrorConditionException
    *          if the underlying delegate is not scrolling.
    */
   @Override
   public void setIndexedReposition()
   {      
      if (!indexedReposition)
      {
         setDelegateIndexedReposition();
         indexedReposition = true;
      }
   }
   
   /**
    * Indicate whether this query is optimized using indexed reposition.
    *
    * @return  <code>true</code> if this query is indexed reposition.
    */
   @Override
   public boolean isIndexedReposition()
   {
      return indexedReposition;
   }
   
   /**
    * Open the prepared query delegate.
    */
   public void open()
   {
      notifyBeforeOpenListeners();
      
      this.closed = false;
      this.advanced = false;
      
      if (browsed)
      {
         fetchOnReposition = true;
         delegate.setFetchOnReposition(true);
      }
      
      delegate.open();
      
      if (!browsed && delegate.isNativelyPreselect())
      {
         delegate.releaseBuffers();
      }
      
      if (!(cleanerRegistered || dynamic || dynamicDelegate))
      {
         registerCleaner();
      }
      
      offEnd = delegate._isOffEnd();
   }
   
   /**
    * Explicitly close the prepared query delegate.
    */
   public void close()
   {
      notifyRepositionListeners(true, false, -1);
      
      delegate.close(true);
      this.fetchOnReposition = false;
      this.closed = true;
      // release the reference, if not valid
      if (!valid)
      {
         delegate = null;
      }
   }

   /**
    * Reset the query (this does not close the query).
    */
   @Override
   public void resetQuery()
   {
      this.prepareString = null;
      unregisterBufferRelatedQueries();
      buffers.clear();
   }

   /**
    * Get the number of tables joined by this query.
    * 
    * @return  Number of tables joined by this query.
    */
   public int getTableCount()
   {
      return delegate.getTableCount();
   }
   
   /**
    * Get all the off-end listeners associated with this query.
    * 
    * @return  the off-end listeners associated with this query.
    */
   public ArrayList<QueryOffEndListener> getOffEndListeners()
   {
      return delegate.getOffEndListeners();
   }
   
   /**
    * Add one or more buffers to the list of those which this query references externally. These
    * typically will be buffers referenced by converted CAN-FIND expressions embedded in the
    * query's HQL expression, which are not the primary buffers associated with the query.
    * 
    * @param   dmos
    *          One or more external buffers.
    * 
    * @return  This query wrapper.
    */
   public P2JQuery addExternalBuffers(DataModelObject... dmos)
   {
      delegate.addExternalBuffers(dmos);
      
      return this;
   }
   
   /**
    * Adds an alternative execution query, for the multi-tenant case in which the CAN-FIND nested buffer and
    * the main buffer of query component do not belong to same physical database.
    * <p>
    * This method will be generated only in case of multi-tenant projects, in the condition above-mentioned.
    *
    * @param   where
    *          FQL where clause.  May be {@code null}.
    * @param   whereExpr
    *          Client-side where clause expression. May be {@code null} but this is probably caused by an
    *          incorrect conversion.
    * @param   sort
    *          The sort order.
    * @param   args
    *          Substitution parameters for FQL queries. These will be used if not overridden by a record
    *          retrieval method.
    *
    * @return  Self object so that the call to this method can be optionally chained with the constructor.
    */
   @Override
   public P2JQuery setMultiTenantAlternative(String where,
                                             Supplier<logical> whereExpr,
                                             String sort,
                                             Object[] args)
   {
      delegate.setMultiTenantAlternative(where, whereExpr, sort, args);
      return this;
   }
   
   /**
    * Adds an alternative execution query, for the multi-tenant case in which the CAN-FIND nested buffer and
    * the main buffer of query component do not belong to same physical database.
    * <p>
    * This method will be generated only in case of multi-tenant projects, in the condition above-mentioned.
    *
    * @param   where
    *          FQL where clause.  May be {@code null}.
    * @param   whereExpr
    *          Client-side where clause expression. May be {@code null} but this is probably caused by an
    *          incorrect conversion.
    * @param   sort
    *          The sort order.
    *
    * @return  Self object so that the call to this method can be optionally chained with the constructor.
    */
   @Override
   public P2JQuery setMultiTenantAlternative(String where, Supplier<logical> whereExpr, String sort)
   {
      delegate.setMultiTenantAlternative(where, whereExpr, sort);
      return this;
   }
   
   /**
    * Set a mode on the underlying buffers such that setting a null record
    * into a buffer may or may not result in an error condition.  This applies
    * only to <code>FIRST</code>, <code>LAST</code>, and <code>UNIQUE</code>
    * iteration types.
    * <p>
    * If a query delegate has already been set, it is updated with the new
    * setting immediately.  The setting is remembered, such that any delegate
    * assigned after this method is invoked will have this setting updated
    * upon assignment to the query wrapper.
    *
    * @param   errorIfNull
    *          If <code>true</code>, setting a <code>null</code> value as the
    *          current record in an underlying buffer will raise an error
    *          condition (if not in silent error mode); if <code>false</code>,
    *          this action will raise an end condition instead.
    */
   public void setErrorIfNull(boolean errorIfNull)
   {
      this.errorIfNull = errorIfNull;
      if (delegate != null)
      {
         getDelegate().setErrorIfNull(errorIfNull);
      }
   }
   
   /**
    * Add a joinable query to a compound query.  If this is not the first
    * component to be added to the query, its results will be joined to the
    * immediately previous component by an inner join.  This query will be
    * iterated using the <code>NEXT</code> iteration type.
    *
    * @param   query
    *          Query which will perform the fundamental work for this
    *          component when the compound query is iterated.
    *
    * @throws  IllegalStateException
    *          if this method is invoked during an iteration cycle or if
    *          delegate is not an instance of <code>CompoundQuery</code>.
    *
    * @see     #iterate
    */
   public void addComponent(Joinable query)
   {
      compoundDelegate().addComponent(query);
   }
   
   /**
    * Add a joinable query to a compound query, and specify the nature of
    * the iteration which will be performed (first, last, next, etc.) on that
    * component, when the compound query is iterated.  If this is not the
    * first component to be added to the query, its results will be joined to
    * the immediately previous component by an inner join.
    *
    * @param   query
    *          Query which will perform the fundamental work for this
    *          component when the compound query is iterated.
    * @param   iteration
    *          A {@link QueryConstants constant} indicating the type of work
    *          to be performed upon an iteration of the compound query.  This
    *          parameter determines whether the underlying query will be asked
    *          to perform a first, last, next, previous, or unique record
    *          retrieval.
    *
    * @throws  IllegalStateException
    *          if this method is invoked during an iteration cycle or if
    *          delegate is not an instance of <code>CompoundQuery</code>.
    *
    * @see     #iterate
    */
   public void addComponent(Joinable query, int iteration)
   {
      compoundDelegate().addComponent(query, iteration);
   }
   
   /**
    * Add a joinable query to a compound query, and specify the nature of
    * the iteration which will be performed (first, last, next, etc.) on that
    * component, when the compound query is iterated.  If this is not the
    * first component to be added to the query, the type of join performed
    * with the immediately previous component is determined by the value of
    * <code>outer</code>.
    *
    * @param   query
    *          Query which will perform the fundamental work for this
    *          component when the compound query is iterated.
    * @param   iteration
    *          A {@link QueryConstants constant} indicating the type of work
    *          to be performed upon an iteration of the compound query.  This
    *          parameter determines whether the underlying query will be asked
    *          to perform a first, last, next, previous, or unique record
    *          retrieval.
    * @param   outer
    *          <code>true</code> if this component should be joined to the
    *          previously added component via a left outer join;
    *          <code>false</code> if an inner join is required.  Note that
    *          adding an inner join component will cause any previously added
    *          components added as outer joins to be reset to inner joins.
    *
    * @throws  IllegalStateException
    *          if this method is invoked during an iteration cycle or if
    *          delegate is not an instance of <code>CompoundQuery</code>.
    *
    * @see     #iterate
    */
   public void addComponent(Joinable query, int iteration, boolean outer)
   {
      compoundDelegate().addComponent(query, iteration, outer);
   }
   
   /**
    * Add a component to a preselect query.  The following defaults are used:
    * <ul>
    *   <li>no substitution parameters
    *   <li>share lock
    *   <li>inner join
    *   <li><code>NEXT</code> iteration type
    * </ul>
    *
    * @param   dmo
    *          DMO proxy which defines buffer and record type.
    * @param   where
    *          HQL where clause.  May be <code>null</code>.
    *
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>PreselectQuery</code>.
    */
   public void addComponent(DataModelObject dmo, String where)
   {
      addBuffer((Buffer) dmo, true);
      preselectDelegate().addComponent(dmo, where);
   }
   
   /**
    * Add a component to a preselect query.  The following defaults are used:
    * <ul>
    *   <li>no substitution parameters
    *   <li>share lock
    *   <li>inner join
    *   <li><code>NEXT</code> iteration type
    * </ul>
    *
    * @param   dmo
    *          DMO proxy which defines buffer and record type.
    * @param   where
    *          HQL where clause.  May be <code>null</code>.
    * @param   indexInfo
    *          Index information string as it is returned by INDEX-INFORMATION.
    *          May be <code>null</code> if it is not an OPEN QUERY case or if
    *          you don't need debug information about selected indexes.
    *
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>PreselectQuery</code>.
    */
   public void addComponent(DataModelObject dmo, String where, String indexInfo)
   {
      addBuffer((Buffer) dmo, true);
      preselectDelegate().addComponent(dmo, where, indexInfo);
   }
   
   /**
    * Add a component to a preselect query.  The following defaults are used:
    * <ul>
    *   <li>no substitution parameters
    *   <li>share lock
    *   <li>inner join
    *   <li><code>NEXT</code> iteration type
    * </ul>
    *
    * @param   dmo
    *          DMO proxy which defines buffer and record type.
    * @param   where
    *          HQL where clause.  May be <code>null</code>.
    * @param   inverse
    *          DMO to which this query should join via a foreign relation.
    *          May be <code>null</code>.
    *
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>PreselectQuery</code>.
    */
   public void addComponent(DataModelObject dmo,
                            String where,
                            DataModelObject inverse)
   {
      addBuffer((Buffer) dmo, true);
      preselectDelegate().addComponent(dmo, where, inverse);
   }
   
   /**
    * Add a component to a preselect query.  The following defaults are used:
    * <ul>
    *   <li>no substitution parameters
    *   <li>share lock
    *   <li>inner join
    *   <li><code>NEXT</code> iteration type
    * </ul>
    *
    * @param   dmo
    *          DMO proxy which defines buffer and record type.
    * @param   where
    *          HQL where clause.  May be <code>null</code>.
    * @param   indexInfo
    *          Index information string as it is returned by INDEX-INFORMATION.
    *          May be <code>null</code> if it is not an OPEN QUERY case or if
    *          you don't need debug information about selected indexes.
    * @param   inverse
    *          DMO to which this query should join via a foreign relation.
    *          May be <code>null</code>.
    *
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>PreselectQuery</code>.
    */
   public void addComponent(DataModelObject dmo,
                            String where,
                            String indexInfo,
                            DataModelObject inverse)
   {
      addBuffer((Buffer) dmo, true);
      preselectDelegate().addComponent(dmo, where, indexInfo, inverse);
   }
   
   /**
    * Add a component to a preselect query.  The following defaults are used:
    * <ul>
    *   <li>share lock
    *   <li>inner join
    *   <li><code>NEXT</code> iteration type
    * </ul>
    *
    * @param   dmo
    *          DMO proxy which defines buffer and record type.
    * @param   where
    *          HQL where clause.  May be <code>null</code>.
    * @param   args
    *          Substitution parameters to be inserted into placeholders within
    *          the where clause.
    *
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>PreselectQuery</code>.
    */
   public void addComponent(DataModelObject dmo, String where, Object[] args)
   {
      addBuffer((Buffer) dmo, true);
      preselectDelegate().addComponent(dmo, where, args);
   }
   
   /**
    * Add a component to a preselect query.  The following defaults are used:
    * <ul>
    *   <li>share lock
    *   <li>inner join
    *   <li><code>NEXT</code> iteration type
    * </ul>
    *
    * @param   dmo
    *          DMO proxy which defines buffer and record type.
    * @param   where
    *          HQL where clause.  May be <code>null</code>.
    * @param   indexInfo
    *          Index information string as it is returned by INDEX-INFORMATION.
    *          May be <code>null</code> if it is not an OPEN QUERY case or if
    *          you don't need debug information about selected indexes.
    * @param   args
    *          Substitution parameters to be inserted into placeholders within
    *          the where clause.
    *
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>PreselectQuery</code>.
    */
   public void addComponent(DataModelObject dmo, String where, String indexInfo, Object[] args)
   {
      addBuffer((Buffer) dmo, true);
      preselectDelegate().addComponent(dmo, where, indexInfo, args);
   }
   
   /**
    * Add a component to a preselect query.  The following defaults are used:
    * <ul>
    *   <li>share lock
    *   <li>inner join
    *   <li><code>NEXT</code> iteration type
    * </ul>
    *
    * @param   dmo
    *          DMO proxy which defines buffer and record type.
    * @param   where
    *          HQL where clause.  May be <code>null</code>.
    * @param   inverse
    *          DMO to which this query should join via a foreign relation.
    *          May be <code>null</code>.
    * @param   args
    *          Substitution parameters to be inserted into placeholders within
    *          the where clause.
    *
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>PreselectQuery</code>.
    */
   public void addComponent(DataModelObject dmo,
                            String where,
                            DataModelObject inverse,
                            Object[] args)
   {
      addBuffer((Buffer) dmo, true);
      preselectDelegate().addComponent(dmo, where, inverse, args);
   }
   
   /**
    * Add a component to a preselect query.  The following defaults are used:
    * <ul>
    *   <li>share lock
    *   <li>inner join
    *   <li><code>NEXT</code> iteration type
    * </ul>
    *
    * @param   dmo
    *          DMO proxy which defines buffer and record type.
    * @param   where
    *          HQL where clause.  May be <code>null</code>.
    * @param   indexInfo
    *          Index information string as it is returned by INDEX-INFORMATION.
    *          May be <code>null</code> if it is not an OPEN QUERY case or if
    *          you don't need debug information about selected indexes.
    * @param   inverse
    *          DMO to which this query should join via a foreign relation.
    *          May be <code>null</code>.
    * @param   args
    *          Substitution parameters to be inserted into placeholders within
    *          the where clause.
    *
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>PreselectQuery</code>.
    */
   public void addComponent(DataModelObject dmo,
                            String where,
                            String indexInfo,
                            DataModelObject inverse,
                            Object[] args)
   {
      addBuffer((Buffer) dmo, true);
      preselectDelegate().addComponent(dmo, where, indexInfo, inverse, args);
   }
   
   /**
    * Add a component to a preselect query.  The following defaults are used:
    * <ul>
    *   <li>no substitution parameters
    *   <li>inner join
    *   <li><code>NEXT</code> iteration type
    * </ul>
    *
    * @param   dmo
    *          DMO proxy which defines buffer and record type.
    * @param   where
    *          HQL where clause.  May be <code>null</code>.
    * @param   lockType
    *          Lock type to apply to records retrieved by this component of
    *          the query.
    *
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>PreselectQuery</code>.
    */
   public void addComponent(DataModelObject dmo,
                            String where,
                            LockType lockType)
   {
      addBuffer((Buffer) dmo, true);
      preselectDelegate().addComponent(dmo, where, lockType);
   }
   
   /**
    * Add a component to a preselect query.  The following defaults are used:
    * <ul>
    *   <li>no substitution parameters
    *   <li>inner join
    *   <li><code>NEXT</code> iteration type
    * </ul>
    *
    * @param   dmo
    *          DMO proxy which defines buffer and record type.
    * @param   where
    *          HQL where clause.  May be <code>null</code>.
    * @param   indexInfo
    *          Index information string as it is returned by INDEX-INFORMATION.
    *          May be <code>null</code> if it is not an OPEN QUERY case or if
    *          you don't need debug information about selected indexes.
    * @param   lockType
    *          Lock type to apply to records retrieved by this component of
    *          the query.
    *
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>PreselectQuery</code>.
    */
   public void addComponent(DataModelObject dmo,
                            String where,
                            String indexInfo,
                            LockType lockType)
   {
      addBuffer((Buffer) dmo, true);
      preselectDelegate().addComponent(dmo, where, indexInfo, lockType);
   }
   
   /**
    * Add a component to a preselect query.  The following defaults are used:
    * <ul>
    *   <li>no substitution parameters
    *   <li>inner join
    *   <li><code>NEXT</code> iteration type
    * </ul>
    *
    * @param   dmo
    *          DMO proxy which defines buffer and record type.
    * @param   where
    *          HQL where clause.  May be <code>null</code>.
    * @param   inverse
    *          DMO to which this query should join via a foreign relation.
    *          May be <code>null</code>.
    * @param   lockType
    *          Lock type to apply to records retrieved by this component of
    *          the query.
    *
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>PreselectQuery</code>.
    */
   public void addComponent(DataModelObject dmo,
                            String where,
                            DataModelObject inverse,
                            LockType lockType)
   {
      addBuffer((Buffer) dmo, true);
      preselectDelegate().addComponent(dmo, where, inverse, lockType);
   }
   
   /**
    * Add a component to a preselect query.  The following defaults are used:
    * <ul>
    *   <li>no substitution parameters
    *   <li>inner join
    *   <li><code>NEXT</code> iteration type
    * </ul>
    *
    * @param   dmo
    *          DMO proxy which defines buffer and record type.
    * @param   where
    *          HQL where clause.  May be <code>null</code>.
    * @param   indexInfo
    *          Index information string as it is returned by INDEX-INFORMATION.
    *          May be <code>null</code> if it is not an OPEN QUERY case or if
    *          you don't need debug information about selected indexes.
    * @param   inverse
    *          DMO to which this query should join via a foreign relation.
    *          May be <code>null</code>.
    * @param   lockType
    *          Lock type to apply to records retrieved by this component of
    *          the query.
    *
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>PreselectQuery</code>.
    */
   public void addComponent(DataModelObject dmo,
                            String where,
                            String indexInfo,
                            DataModelObject inverse,
                            LockType lockType)
   {
      addBuffer((Buffer) dmo, true);
      preselectDelegate().addComponent(dmo, where, indexInfo, inverse, lockType);
   }
   
   /**
    * Add a component to a preselect query.  The following defaults are used:
    * <ul>
    *   <li>inner join
    *   <li><code>NEXT</code> iteration type
    * </ul>
    *
    * @param   dmo
    *          DMO proxy which defines buffer and record type.
    * @param   where
    *          HQL where clause.  May be <code>null</code>.
    * @param   args
    *          Substitution parameters to be inserted into placeholders within
    *          the where clause.
    * @param   lockType
    *          Lock type to apply to records retrieved by this component of
    *          the query.
    *
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>PreselectQuery</code>.
    */
   public void addComponent(DataModelObject dmo,
                            String where,
                            Object[] args,
                            LockType lockType)
   {
      addBuffer((Buffer) dmo, true);
      preselectDelegate().addComponent(dmo, where, args, lockType);
   }
   
   /**
    * Add a component to a preselect query.  The following defaults are used:
    * <ul>
    *   <li>inner join
    *   <li><code>NEXT</code> iteration type
    * </ul>
    *
    * @param   dmo
    *          DMO proxy which defines buffer and record type.
    * @param   where
    *          HQL where clause.  May be <code>null</code>.
    * @param   indexInfo
    *          Index information string as it is returned by INDEX-INFORMATION.
    *          May be <code>null</code> if it is not an OPEN QUERY case or if
    *          you don't need debug information about selected indexes.
    * @param   args
    *          Substitution parameters to be inserted into placeholders within
    *          the where clause.
    * @param   lockType
    *          Lock type to apply to records retrieved by this component of
    *          the query.
    *
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>PreselectQuery</code>.
    */
   public void addComponent(DataModelObject dmo,
                            String where,
                            String indexInfo,
                            Object[] args,
                            LockType lockType)
   {
      addBuffer((Buffer) dmo, true);
      preselectDelegate().addComponent(dmo, where, indexInfo, args, lockType);
   }
   
   /**
    * Add a component to a preselect query.  The following defaults are used:
    * <ul>
    *   <li>inner join
    *   <li><code>NEXT</code> iteration type
    * </ul>
    *
    * @param   dmo
    *          DMO proxy which defines buffer and record type.
    * @param   where
    *          HQL where clause.  May be <code>null</code>.
    * @param   inverse
    *          DMO to which this query should join via a foreign relation.
    *          May be <code>null</code>.
    * @param   args
    *          Substitution parameters to be inserted into placeholders within
    *          the where clause.
    * @param   lockType
    *          Lock type to apply to records retrieved by this component of
    *          the query.
    *
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>PreselectQuery</code>.
    */
   public void addComponent(DataModelObject dmo,
                            String where,
                            DataModelObject inverse,
                            Object[] args,
                            LockType lockType)
   {
      addBuffer((Buffer) dmo, true);
      preselectDelegate().addComponent(dmo, where, inverse, args, lockType);
   }
   
   /**
    * Add a component to a preselect query.  The following defaults are used:
    * <ul>
    *   <li>inner join
    *   <li><code>NEXT</code> iteration type
    * </ul>
    *
    * @param   dmo
    *          DMO proxy which defines buffer and record type.
    * @param   where
    *          HQL where clause.  May be <code>null</code>.
    * @param   indexInfo
    *          Index information string as it is returned by INDEX-INFORMATION.
    *          May be <code>null</code> if it is not an OPEN QUERY case or if
    *          you don't need debug information about selected indexes.
    * @param   inverse
    *          DMO to which this query should join via a foreign relation.
    *          May be <code>null</code>.
    * @param   args
    *          Substitution parameters to be inserted into placeholders within
    *          the where clause.
    * @param   lockType
    *          Lock type to apply to records retrieved by this component of
    *          the query.
    *
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>PreselectQuery</code>.
    */
   public void addComponent(DataModelObject dmo,
                            String where,
                            String indexInfo,
                            DataModelObject inverse,
                            Object[] args,
                            LockType lockType)
   {
      addBuffer((Buffer) dmo, true);
      preselectDelegate().addComponent(dmo, where, indexInfo, inverse, args, lockType);
   }
   
   /**
    * Add a component to a preselect query.
    *
    * @param   dmo
    *          DMO proxy which defines buffer and record type.
    * @param   where
    *          HQL where clause.  May be <code>null</code>.
    * @param   args
    *          Substitution parameters to be inserted into placeholders within
    *          the where clause.
    * @param   lockType
    *          Lock type to apply to records retrieved by this component of
    *          the query.
    * @param   iteration
    *          Iteration/retrieval mode for this component of the query.  At
    *          this time, only <code>NEXT</code> is supported.  Future
    *          support for <code>FIRST</code>, <code>LAST</code>, and
    *          <code>UNIQUE</code> is expected.
    * @param   outer
    *          <code>true</code> if an outer join is required.  At this time,
    *          only inner joins are supported.  Future support for outer
    *          joins is expected.
    *
    * @throws  UnsupportedOperationException
    *          if <code>outer</code> is <code>true</code> (temporary);
    *          if <code>iteration</code> is not <code>NEXT</code> (temporary);
    *          if <code>dmo</code>'s associated database is different than
    *          that of a previously added component's database (cross-database
    *          preselect joins are not possible).
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>PreselectQuery</code>.
    */
   public void addComponent(DataModelObject dmo,
                            String where,
                            Object[] args,
                            LockType lockType,
                            int iteration,
                            boolean outer)
   {
      addBuffer((Buffer) dmo, true);
      preselectDelegate().addComponent(dmo,
                                       where,
                                       args,
                                       lockType,
                                       iteration,
                                       outer);
   }
   
   /**
    * Add a component to a preselect query.
    *
    * @param   dmo
    *          DMO proxy which defines buffer and record type.
    * @param   where
    *          HQL where clause.  May be <code>null</code>.
    * @param   indexInfo
    *          Index information string as it is returned by INDEX-INFORMATION.
    *          May be <code>null</code> if it is not an OPEN QUERY case or if
    *          you don't need debug information about selected indexes.
    * @param   args
    *          Substitution parameters to be inserted into placeholders within
    *          the where clause.
    * @param   lockType
    *          Lock type to apply to records retrieved by this component of
    *          the query.
    * @param   iteration
    *          Iteration/retrieval mode for this component of the query.  At
    *          this time, only <code>NEXT</code> is supported.  Future
    *          support for <code>FIRST</code>, <code>LAST</code>, and
    *          <code>UNIQUE</code> is expected.
    * @param   outer
    *          <code>true</code> if an outer join is required.  At this time,
    *          only inner joins are supported.  Future support for outer
    *          joins is expected.
    *
    * @throws  UnsupportedOperationException
    *          if <code>outer</code> is <code>true</code> (temporary);
    *          if <code>iteration</code> is not <code>NEXT</code> (temporary);
    *          if <code>dmo</code>'s associated database is different than
    *          that of a previously added component's database (cross-database
    *          preselect joins are not possible).
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>PreselectQuery</code>.
    */
   public void addComponent(DataModelObject dmo,
                            String where,
                            String indexInfo,
                            Object[] args,
                            LockType lockType,
                            int iteration,
                            boolean outer)
   {
      addBuffer((Buffer) dmo, true);
      preselectDelegate().addComponent(dmo,
                                       where,
                                       indexInfo,
                                       args,
                                       lockType,
                                       iteration,
                                       outer);
   }
   
   /**
    * Add a component to a preselect query.
    *
    * @param   dmo
    *          DMO proxy which defines buffer and record type.
    * @param   where
    *          HQL where clause.  May be <code>null</code>.
    * @param   inverse
    *          DMO to which this query should join via a foreign relation.
    *          May be <code>null</code>.
    * @param   args
    *          Substitution parameters to be inserted into placeholders within
    *          the where clause.
    * @param   lockType
    *          Lock type to apply to records retrieved by this component of
    *          the query.
    * @param   iteration
    *          Iteration/retrieval mode for this component of the query.  At
    *          this time, only <code>NEXT</code> is supported.  Future
    *          support for <code>FIRST</code>, <code>LAST</code>, and
    *          <code>UNIQUE</code> is expected.
    * @param   outer
    *          <code>true</code> if an outer join is required.  At this time,
    *          only inner joins are supported.  Future support for outer
    *          joins is expected.
    *
    * @throws  UnsupportedOperationException
    *          if <code>outer</code> is <code>true</code> (temporary);
    *          if <code>iteration</code> is not <code>NEXT</code> (temporary);
    *          if <code>dmo</code>'s associated database is different than
    *          that of a previously added component's database (cross-database
    *          preselect joins are not possible).
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>PreselectQuery</code>.
    */
   public void addComponent(DataModelObject dmo,
                            String where,
                            DataModelObject inverse,
                            Object[] args,
                            LockType lockType,
                            int iteration,
                            boolean outer)
   {
      addBuffer((Buffer) dmo, true);
      preselectDelegate().addComponent(dmo,
                                       where,
                                       inverse,
                                       args,
                                       lockType,
                                       iteration,
                                       outer);
   }
   
   /**
    * Add a component to a preselect query.
    *
    * @param   dmo
    *          DMO proxy which defines buffer and record type.
    * @param   where
    *          HQL where clause.  May be <code>null</code>.
    * @param   indexInfo
    *          Index information string as it is returned by INDEX-INFORMATION.
    *          May be <code>null</code> if it is not an OPEN QUERY case or if
    *          you don't need debug information about selected indexes.
    * @param   inverse
    *          DMO to which this query should join via a foreign relation.
    *          May be <code>null</code>.
    * @param   args
    *          Substitution parameters to be inserted into placeholders within
    *          the where clause.
    * @param   lockType
    *          Lock type to apply to records retrieved by this component of
    *          the query.
    * @param   iteration
    *          Iteration/retrieval mode for this component of the query.  At
    *          this time, only <code>NEXT</code> is supported.  Future
    *          support for <code>FIRST</code>, <code>LAST</code>, and
    *          <code>UNIQUE</code> is expected.
    * @param   outer
    *          <code>true</code> if an outer join is required.  At this time,
    *          only inner joins are supported.  Future support for outer
    *          joins is expected.
    *
    * @throws  UnsupportedOperationException
    *          if <code>outer</code> is <code>true</code> (temporary);
    *          if <code>iteration</code> is not <code>NEXT</code> (temporary);
    *          if <code>dmo</code>'s associated database is different than
    *          that of a previously added component's database (cross-database
    *          preselect joins are not possible).
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>PreselectQuery</code>.
    */
   public void addComponent(DataModelObject dmo,
                            String where,
                            String indexInfo,
                            DataModelObject inverse,
                            Object[] args,
                            LockType lockType,
                            int iteration,
                            boolean outer)
   {
      addBuffer((Buffer) dmo, true);
      preselectDelegate().addComponent(dmo,
                                       where,
                                       indexInfo,
                                       inverse,
                                       args,
                                       lockType,
                                       iteration,
                                       outer);
   }
   
   /**
    * Add a client-side where expression to a preselect query.  Each initial
    * query result found by the server must be accepted by this expression
    * before becoming a part of the query's final result set.
    *
    * @param   whereExpr
    *          Client-side where clause expression.  May not be
    *          <code>null</code>.
    *
    * @throws  NullPointerException
    *          if <code>whereExpr</code> is <code>null</code>.
    *
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>PreselectQuery</code>.
    */
   public void addWhereExpression(Supplier<logical> whereExpr)
   {
      preselectDelegate().addWhereExpression(whereExpr);
   }
   
   /**
    * Set the iteration type for the most recently added query component to a preselect query.
    *
    * @param   iteration
    *          Retrieval mode from {@link QueryConstants}. Must not be FIRST or LAST (use
    *          {@link #setIterationType(int, String)} instead for these types.
    *
    * @throws  IllegalStateException
    *          if no component has yet been added; or
    *          if delegate is not an instance of <code>PreselectQuery</code>.
    * @throws  IllegalArgumentException
    *          if <code>iteration</code> type is <code>FIRST</code> or <code>LAST</code>.
    */
   public void setIterationType(int iteration)
   {
      preselectDelegate().setIterationType(iteration);
   }
   
   /**
    * Set the iteration type for the most recently added query component to a preselect query.
    *
    * @param   iteration
    *          Retrieval mode from {@link QueryConstants}.
    * @param   sort
    *          Order by clause which should be associated with the most recently added query
    *          component. Must be non-<code>null</code> for iteration types <code>FIRST</code>
    *          and <code>LAST</code>.
    *
    * @throws  IllegalStateException
    *          if no component has yet been added; or
    *          if delegate is not an instance of <code>PreselectQuery</code>.
    * @throws  IllegalArgumentException
    *          if <code>iteration</code> type is <code>FIRST</code> or <code>LAST</code>, but
    *          <code>sort</code> is <code>null</code>, or if <code>sort</code> represents an
    *          invalid HQL order by expression.
    */
   public void setIterationType(int iteration, String sort)
   {
      preselectDelegate().setIterationType(iteration, sort);
   }
   
   /**
    * Add a single sort criterion, in the form of a <code>Resolvable</code>
    * object which is resolved at sort time.  It is the value of the resolved
    * result which is used for the sort.
    * <p>
    * The sort is ascending, from lowest resolved value to highest.
    * <p>
    * The delegate must be an instance of <code>PresortDelegate</code>
    *
    * @param   sort
    *          A resolvable object whose resolved result is used for sorting.
    *
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>PresortDelegate</code>.
    */
   public void addSortCriterion(Resolvable sort)
   {
      presortDelegate().addSortCriterion(sort);
   }
   
   /**
    * Add a single sort criterion, in the form of a <code>Resolvable</code>
    * object which is resolved at runtime.  It is the value of the resolved
    * result which is used for the sort.
    * <p>
    * The delegate must be an instance of <code>PresortDelegate</code>
    *
    * @param   sort
    *          A resolvable object whose resolved result is used for sorting.
    * @param   descending
    *          if <code>true</code>, the sort is descending, from highest
    *          resolved value to lowest;  otherwise, the sort is ascending.
    *
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>PresortDelegate</code>.
    */
   public void addSortCriterion(Resolvable sort, boolean descending)
   {
      presortDelegate().addSortCriterion(sort, descending);
   }
   
   /**
    * Set the behavior of this query as a record retrieval request moves off
    * the end of its results.  If set to lenient mode, invocations of
    * <code>next</code> and <code>previous</code> which do not find a record
    * do not raise a <code>QueryOffEndException</code>.  By default, this
    * would normally raise the exception.
    *
    * @param   lenientOffEnd
    *          <code>true</code> to suppress <code>QueryOffEndException</code>
    *          for <code>next</code> and <code>previous</code> requests;
    *          <code>false</code> to permit these exceptions.
    */
   @Override
   public void setLenientOffEnd(boolean lenientOffEnd)
   {
      getDelegate().setLenientOffEnd(lenientOffEnd);
   }
   
   /**
    * Enable all sort criteria set for this query to act as break group
    * categories.  When the query's results are presorted, the contents of
    * each break group are determined.
    * <p>
    * The delegate must be an instance of <code>PresortDelegate</code>
    *
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>PresortDelegate</code>.
    */
   public void enableBreakGroups()
   {
      presortDelegate().enableBreakGroups();
   }
   
   /**
    * Add an accumulator to this query.  The accumulator expects to be
    * notified whenever a new result row is accessed (during sequential row
    * access).
    * <p>
    * This implementation assumes the accumulator is not associated with a
    * break group.
    *
    * @param   accum
    *          Accumulator to be registered with this query.
    */
   public void addAccumulator(Accumulator accum)
   {
      getDelegate().addAccumulator(accum);
   }
   
   /**
    * Add an accumulator to this query.  The accumulator expects to be
    * notified whenever a new result row is accessed (during sequential row
    * access).
    * <p>
    * This implementation assumes the accumulator is not associated with a
    * break group.
    *
    * @param   accum
    *          Accumulator to be registered with this query.
    * @param   deferred
    *          If <code>true</code>, calls to {@link #iterate()} will not
    *          cause the accumulator to recalculate immediately, but instead
    *          to update the accumulator's state such that the next invocation
    *          of {@link com.goldencode.p2j.util.Accumulator#accumulate()} will
    *          trigger the actual accumulation update.  If <code>false</code>,
    *          the accumulator recalculates its internal state immediately
    */
   public void addAccumulator(Accumulator accum, boolean deferred)
   {
      getDelegate().addAccumulator(accum, deferred);
   }
   
   /**
    * Reports if this query (that is, its delegate query) is valid for use.
    *
    * @return  <code>true</code> if this query's delegate is valid for use.
    */
   public boolean valid()
   {
      return valid;
   }
   
   /**
    * Advance a compound query, triggering one or more of the underlying
    * queries to retrieve a new record.  This produces a virtual, composite
    * row of results which is the combination of the records retrieved by
    * each component query.
    *
    * @throws  QueryOffEndException
    *          if no more records can be retrieved by the underlying queries.
    * @throws  ErrorConditionException
    *          if an underlying query triggers an error.
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>CompoundQuery</code>.
    */
   public void iterate()
   {
      compoundDelegate().iterate();
   }
   
   /**
    * Navigate to the first record which meets the query criteria and retrieve
    * it into its record buffer.  Use the default substitution parameters and
    * lock type.
    *
    * @throws  ErrorConditionException
    *          if an error occurred during record retrieval or if no record
    *          could be found when operating in standalone mode.
    */
   public boolean first()
   {
      if (!canGetStmt() || !canGetFirst())
      {
         return false;
      }
      
      advanced = true;
      
      boolean available = false;
      available = logical.of(getDelegate().first()).booleanValue();
      maybeFireCallback();
      
      return available;
   }
   
   /**
    * Navigate to the first record which meets the query criteria and retrieve
    * it into its record buffer.  Use the default substitution parameters, but
    * override the default lock type with that provided.
    *
    * @param   lockType
    *          Lock type to acquire for the retrieved record.
    *
    * @throws  ErrorConditionException
    *          if an error occurred during record retrieval or if no record
    *          could be found when operating in standalone mode.
    */
   public boolean first(LockType lockType)
   {
      if (!canGetStmt() || !canGetFirst())
      {
         return false;
      }
      
      advanced = true;
      boolean available = logical.of(getDelegate().first(lockType)).booleanValue();
      maybeFireCallback();
      
      return available;
   }
   
   /**
    * Retrieve the first virtual, composite row of results for a compound
    * query.
    * <p>
    * This is a combination of records retrieved by each component query.  If
    * the compound query involves outer joins, some of the underlying buffers
    * may be empty when this method returns.
    *
    * @param   iterating
    *          <code>true</code> if this method is being invoked within the
    *          context of an iterating loop, which can only be exited by
    *          raising an end condition;  <code>false</code> if end condition
    *          should not be raised, even if no further advancement of the
    *          composite result is possible.
    *
    * @throws  QueryOffEndException
    *          if no more results were available in iterating mode.
    * @throws  ErrorConditionException
    *          if an underlying query triggers an error.
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>CompoundQuery</code>.
    */
   public boolean first(boolean iterating)
   {
      return compoundDelegate().first(iterating);
   }
   
   /**
    * Retrieve the first virtual, composite row of results for a compound
    * query, overriding the lock type to apply to each underlying query.
    * <p>
    * This is a combination of records retrieved by each component query.  If
    * the compound query involves outer joins, some of the underlying buffers
    * may be empty when this method returns.
    *
    * @param   iterating
    *          <code>true</code> if this method is being invoked within the
    *          context of an iterating loop, which can only be exited by
    *          raising an end condition;  <code>false</code> if end condition
    *          should not be raised, even if no further advancement of the
    *          composite result is possible.
    * @param   lockType
    *          Lock type which should override that of any underlying query.
    *
    * @throws  QueryOffEndException
    *          if no more results were available in iterating mode.
    * @throws  ErrorConditionException
    *          if an underlying query triggers an error.
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>CompoundQuery</code>.
    */
   public boolean first(boolean iterating, LockType lockType)
   {
      return compoundDelegate().first(iterating, lockType);
   }
   
   /**
    * Navigate to the first record which meets the query criteria and retrieve
    * it into its record buffer.  Use the default lock type, but override the
    * default substitution parameters with those provided.
    * <p>
    * The delegate must be an instance of <code>RandomAccessQuery</code>
    *
    * @param   values
    *          Substitution values to use when issuing HQL queries.
    *
    * @throws  ErrorConditionException
    *          if an error occurred during record retrieval or if no record
    *          could be found when operating in standalone mode.
    * @throws  QueryOffEndException
    *          if no record could be found when operating in compound query
    *          mode.
    * @throws  IllegalStateException
    *          if delegate is not an instance of
    *          <code>RandomAccessQuery</code>.
    */
   public boolean first(Object[] values)
   {
      return randomAccessDelegate().first(values);
   }
   
   /**
    * Navigate to the first record which meets the query criteria and retrieve
    * it into its record buffer.  Override both the default substitution
    * parameters, and the default lock type with those provided.
    * <p>
    * The delegate must be an instance of <code>RandomAccessQuery</code>
    *
    * @param   values
    *          Substitution values to use when issuing HQL queries.
    * @param   lockType
    *          Lock type to acquire for the retrieved record.
    *
    * @throws  ErrorConditionException
    *          if an error occurred during record retrieval or if no record
    *          could be found when operating in standalone mode.
    * @throws  QueryOffEndException
    *          if no record could be found when operating in compound query
    *          mode.
    * @throws  IllegalStateException
    *          if delegate is not an instance of
    *          <code>RandomAccessQuery</code>.
    */
   public boolean first(Object[] values, LockType lockType)
   {
      return randomAccessDelegate().first(values, lockType);
   }
   
   /**
    * Navigate to the last record which meets the query criteria and retrieve
    * it into its record buffer.  Use the default substitution parameters and
    * lock type.
    *
    * @throws  ErrorConditionException
    *          if an error occurred during record retrieval or if no record
    *          could be found when operating in standalone mode.
    */
   public boolean last()
   {
      if (!canGetStmt() || !canLastOrPrev())
      {
         return false;
      }
      
      return logical.of(getDelegate().last()).booleanValue();
   }
   
   /**
    * Navigate to the last record which meets the query criteria and retrieve
    * it into its record buffer.  Use the default substitution parameters, but
    * override the default lock type with that provided.
    *
    * @param   lockType
    *          Lock type to acquire for the retrieved record.
    *
    * @throws  ErrorConditionException
    *          if an error occurred during record retrieval or if no record
    *          could be found when operating in standalone mode.
    */
   public boolean last(LockType lockType)
   {
      if (!canGetStmt() || !canLastOrPrev())
      {
         return false;
      }
      
      boolean avail = logical.of(getDelegate().last(lockType)).booleanValue();
      maybeFireCallback();
      return avail;
   }
   
   /**
    * Retrieve the last virtual, composite row of results for a compound
    * query.
    * <p>
    * This is a combination of records retrieved by each component query.  If
    * the compound query involves outer joins, some of the underlying buffers
    * may be empty when this method returns.
    *
    * @param   iterating
    *          <code>true</code> if this method is being invoked within the
    *          context of an iterating loop, which can only be exited by
    *          raising an end condition;  <code>false</code> if end condition
    *          should not be raised, even if no further advancement of the
    *          composite result is possible.
    *
    * @throws  QueryOffEndException
    *          if no more results were available in iterating mode.
    * @throws  ErrorConditionException
    *          if an underlying query triggers an error.
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>CompoundQuery</code>.
    */
   public void last(boolean iterating)
   {
      compoundDelegate().last(iterating);
   }
   
   /**
    * Retrieve the last virtual, composite row of results for a compound
    * query, overriding the lock type to apply to each underlying query.
    * <p>
    * This is a combination of records retrieved by each component query.  If
    * the compound query involves outer joins, some of the underlying buffers
    * may be empty when this method returns.
    *
    * @param   iterating
    *          <code>true</code> if this method is being invoked within the
    *          context of an iterating loop, which can only be exited by
    *          raising an end condition;  <code>false</code> if end condition
    *          should not be raised, even if no further advancement of the
    *          composite result is possible.
    * @param   lockType
    *          Lock type which should override that of any underlying query.
    *
    * @throws  QueryOffEndException
    *          if no more results were available in iterating mode.
    * @throws  ErrorConditionException
    *          if an underlying query triggers an error.
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>CompoundQuery</code>.
    */
   public void last(boolean iterating, LockType lockType)
   {
      compoundDelegate().last(iterating, lockType);
   }
   
   /**
    * Navigate to the last record which meets the query criteria and retrieve
    * it into its record buffer.  Use the default lock type, but override the
    * default substitution parameters with those provided.
    * <p>
    * The delegate must be an instance of <code>RandomAccessQuery</code>
    *
    * @param   values
    *          Substitution values to use when issuing HQL queries.
    *
    * @throws  ErrorConditionException
    *          if an error occurred during record retrieval or if no record
    *          could be found when operating in standalone mode.
    * @throws  QueryOffEndException
    *          if no record could be found when operating in compound query
    *          mode.
    * @throws  IllegalStateException
    *          if delegate is not an instance of
    *          <code>RandomAccessQuery</code>.
    */
   public void last(Object[] values)
   {
      randomAccessDelegate().last(values);
   }
   
   /**
    * Navigate to the last record which meets the query criteria and retrieve
    * it into its record buffer.  Override both the default substitution
    * parameters, and the default lock type with those provided.
    * <p>
    * The delegate must be an instance of <code>RandomAccessQuery</code>
    *
    * @param   values
    *          Substitution values to use when issuing HQL queries.
    * @param   lockType
    *          Lock type to acquire for the retrieved record.
    *
    * @throws  ErrorConditionException
    *          if an error occurred during record retrieval or if no record
    *          could be found when operating in standalone mode.
    * @throws  QueryOffEndException
    *          if no record could be found when operating in compound query
    *          mode.
    * @throws  IllegalStateException
    *          if delegate is not an instance of
    *          <code>RandomAccessQuery</code>.
    */
   public void last(Object[] values, LockType lockType)
   {
      randomAccessDelegate().last(values, lockType);
   }
   
   /**
    * Navigate to the next record which meets the query criteria and retrieve
    * it into its record buffer.  Use the default substitution parameters and
    * lock type.
    * <p>
    * Use the record most recently loaded into the backing buffer as the
    * reference point when determining the next record to visit.  If no
    * record has yet been loaded into the buffer, retrieve the first record
    * which meets the query criteria.
    *
    * @throws  ErrorConditionException
    *          if an error occurred during record retrieval.
    */
   public boolean next()
   {
      if (!canGetStmt())
      {
         return false;
      }
      
      advanced = true;
      
      boolean hasNext = getDelegate().next();
      maybeFireCallback();
      
      return hasNext;
   }
   
   /**
    * Navigate to the next record which meets the query criteria and retrieve
    * it into its record buffer.  Use the default substitution parameters, but
    * override the default lock type with that provided.
    * <p>
    * Use the record most recently loaded into the backing buffer as the
    * reference point when determining the next record to visit.  If no
    * record has yet been loaded into the buffer, retrieve the first record
    * which meets the query criteria.
    *
    * @param   lockType
    *          Lock type to acquire for the retrieved record.
    *
    * @throws  ErrorConditionException
    *          if an error occurred during record retrieval.
    */
   public boolean next(LockType lockType)
   {
      if (!canGetStmt())
      {
         return false;
      }
      
      advanced = true;
      
      boolean hasNext = getDelegate().next(lockType);
      maybeFireCallback();
      
      return hasNext;
   }
   
   /**
    * Retrieve the next virtual, composite row of results for a compound
    * query.
    * <p>
    * This is a combination of records retrieved by each component query.  If
    * the compound query involves outer joins, some of the underlying buffers
    * may be empty when this method returns.
    *
    * @param   iterating
    *          <code>true</code> if this method is being invoked within the
    *          context of an iterating loop, which can only be exited by
    *          raising an end condition;  <code>false</code> if end condition
    *          should not be raised, even if no further advancement of the
    *          composite result is possible.
    *
    * @throws  QueryOffEndException
    *          if no more results were available in iterating mode.
    * @throws  ErrorConditionException
    *          if an underlying query triggers an error.
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>CompoundQuery</code>.
    */
   public boolean next(boolean iterating)
   {
      return compoundDelegate().next(iterating);
   }
   
   /**
    * Retrieve the next virtual, composite row of results for a compound
    * query, overriding the lock type to apply to each underlying query.
    * <p>
    * This is a combination of records retrieved by each component query.  If
    * the compound query involves outer joins, some of the underlying buffers
    * may be empty when this method returns.
    *
    * @param   iterating
    *          <code>true</code> if this method is being invoked within the
    *          context of an iterating loop, which can only be exited by
    *          raising an end condition;  <code>false</code> if end condition
    *          should not be raised, even if no further advancement of the
    *          composite result is possible.
    * @param   lockType
    *          Lock type which should override that of any underlying query.
    *
    * @throws  QueryOffEndException
    *          if no more results were available in iterating mode.
    * @throws  ErrorConditionException
    *          if an underlying query triggers an error.
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>CompoundQuery</code>.
    */
   public boolean next(boolean iterating, LockType lockType)
   {
      return compoundDelegate().next(iterating, lockType);
   }
   
   /**
    * Navigate to the next record which meets the query criteria and retrieve
    * it into its record buffer.  Use the default lock type, but override the
    * default substitution parameters with those provided.
    * <p>
    * Use the record most recently loaded into the backing buffer as the
    * reference point when determining the next record to visit.  If no
    * record has yet been loaded into the buffer, retrieve the first record
    * which meets the query criteria.
    * <p>
    * The delegate must be an instance of <code>RandomAccessQuery</code>
    *
    * @param   values
    *          Substitution values to use when issuing HQL queries.
    *
    * @throws  ErrorConditionException
    *          if an error occurred during record retrieval.
    * @throws  IllegalStateException
    *          if delegate is not an instance of
    *          <code>RandomAccessQuery</code>.
    */
   public boolean next(Object[] values)
   {
      return randomAccessDelegate().next(values);
   }
   
   /**
    * Navigate to the next record which meets the query criteria and retrieve
    * it into its record buffer.  Override both the default substitution
    * parameters, and the default lock type with those provided.
    * <p>
    * Use the record most recently loaded into the backing buffer as the
    * reference point when determining the next record to visit.  If no
    * record has yet been loaded into the buffer, retrieve the first record
    * which meets the query criteria.
    * <p>
    * The delegate must be an instance of <code>RandomAccessQuery</code>
    *
    * @param   values
    *          Substitution values to use when issuing HQL queries.
    * @param   lockType
    *          Lock type to acquire for the retrieved record.
    *
    * @throws  ErrorConditionException
    *          if an error occurred during record retrieval.
    * @throws  IllegalStateException
    *          if delegate is not an instance of
    *          <code>RandomAccessQuery</code>.
    */
   public boolean next(Object[] values, LockType lockType)
   {
      return randomAccessDelegate().next(values, lockType);
   }
   
   /**
    * Navigate to the previous record which meets the query criteria and
    * retrieve it into its record buffer.  Use the default substitution
    * parameters and lock type.
    * <p>
    * Use the record most recently loaded into the backing buffer as the
    * reference point when determining the previous record to visit.  If no
    * record has yet been loaded into the buffer, retrieve the last record
    * which meets the query criteria.
    *
    * @throws  ErrorConditionException
    *          if an error occurred during record retrieval.
    */
   public boolean previous()
   {
      if (!canGetStmt() || !canLastOrPrev())
      {
         return false;
      }
      
      boolean avail = getDelegate().previous();
      maybeFireCallback();
      return avail;
   }
   
   /**
    * Navigate to the previous record which meets the query criteria and
    * retrieve it into its record buffer.  Use the default substitution
    * parameters, but override the default lock type with that provided.
    * <p>
    * Use the record most recently loaded into the backing buffer as the
    * reference point when determining the previous record to visit.  If no
    * record has yet been loaded into the buffer, retrieve the last record
    * which meets the query criteria.
    *
    * @param   lockType
    *          Lock type to acquire for the retrieved record.
    *
    * @throws  ErrorConditionException
    *          if an error occurred during record retrieval.
    */
   public boolean previous(LockType lockType)
   {
      if (!canGetStmt() || !canLastOrPrev())
      {
         return false;
      }
      
      boolean avail = getDelegate().previous(lockType);
      maybeFireCallback();
      
      return avail;
   }
   
   /**
    * Retrieve the previous virtual, composite row of results for a compound
    * query.
    * <p>
    * This is a combination of records retrieved by each component query.  If
    * the compound query involves outer joins, some of the underlying buffers
    * may be empty when this method returns.
    *
    * @param   iterating
    *          <code>true</code> if this method is being invoked within the
    *          context of an iterating loop, which can only be exited by
    *          raising an end condition;  <code>false</code> if end condition
    *          should not be raised, even if no further advancement of the
    *          composite result is possible.
    *
    * @throws  QueryOffEndException
    *          if no more results were available in iterating mode.
    * @throws  ErrorConditionException
    *          if an underlying query triggers an error.
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>CompoundQuery</code>.
    */
   public boolean previous(boolean iterating)
   {
      return compoundDelegate().previous(iterating);
   }
   
   /**
    * Retrieve the previous virtual, composite row of results for a compound
    * query, overriding the lock type to apply to each underlying query.
    * <p>
    * This is a combination of records retrieved by each component query.  If
    * the compound query involves outer joins, some of the underlying buffers
    * may be empty when this method returns.
    *
    * @param   iterating
    *          <code>true</code> if this method is being invoked within the
    *          context of an iterating loop, which can only be exited by
    *          raising an end condition;  <code>false</code> if end condition
    *          should not be raised, even if no further advancement of the
    *          composite result is possible.
    * @param   lockType
    *          Lock type which should override that of any underlying query.
    *
    * @throws  QueryOffEndException
    *          if no more results were available in iterating mode.
    * @throws  ErrorConditionException
    *          if an underlying query triggers an error.
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>CompoundQuery</code>.
    */
   public boolean previous(boolean iterating, LockType lockType)
   {
      return compoundDelegate().previous(iterating, lockType);
   }
   
   /**
    * Navigate to the previous record which meets the query criteria and
    * retrieve it into its record buffer.  Use the default lock type, but
    * override the default substitution parameters with those provided.
    * <p>
    * Use the record most recently loaded into the backing buffer as the
    * reference point when determining the previous record to visit.  If no
    * record has yet been loaded into the buffer, retrieve the last record
    * which meets the query criteria.
    * <p>
    * The delegate must be an instance of <code>RandomAccessQuery</code>
    *
    * @param   values
    *          Substitution values to use when issuing HQL queries.
    *
    * @throws  ErrorConditionException
    *          if an error occurred during record retrieval.
    * @throws  IllegalStateException
    *          if delegate is not an instance of
    *          <code>RandomAccessQuery</code>.
    */
   public boolean previous(Object[] values)
   {
      return randomAccessDelegate().previous(values);
   }
   
   /**
    * Navigate to the previous record which meets the query criteria and
    * retrieve it into its record buffer.  Override both the default
    * substitution parameters, and the default lock type with those provided.
    * <p>
    * Use the record most recently loaded into the backing buffer as the
    * reference point when determining the previous record to visit.  If no
    * record has yet been loaded into the buffer, retrieve the last record
    * which meets the query criteria.
    * <p>
    * The delegate must be an instance of <code>RandomAccessQuery</code>
    *
    * @param   values
    *          Substitution values to use when issuing HQL queries.
    * @param   lockType
    *          Lock type to acquire for the retrieved record.
    *
    * @throws  ErrorConditionException
    *          if an error occurred during record retrieval.
    * @throws  IllegalStateException
    *          if delegate is not an instance of
    *          <code>RandomAccessQuery</code>.
    */
   public boolean previous(Object[] values, LockType lockType)
   {
      return randomAccessDelegate().previous(values, lockType);
   }
   
   /**
    * Reload the record most recently loaded into the backing record buffer,
    * if any.  Use the default lock type.
    *
    * @throws  ErrorConditionException
    *          if an error occurred during record reload.
    */
   public boolean current()
   {
      if (!canGetStmt())
      {
         return false;
      }
      
      boolean available = getDelegate().current();
      maybeFireCallback();
      
      return available;
   }
   
   /**
    * Reload the record most recently loaded into the backing record buffer,
    * if any.  Override the default lock type.
    *
    * @param   lockType
    *          New lock type to apply to the record.
    *
    * @throws  ErrorConditionException
    *          if an error occurred during record reload, or the lock could
    *          not be transitioned to the requested type.
    */
   public boolean current(LockType lockType)
   {
      if (!canGetStmt())
      {
         return false;
      }
      
      boolean available = getDelegate().current(lockType);
      maybeFireCallback();
      
      return available;
   }
   
   /**
    * Navigate to a particular record which meets the query criteria and
    * retrieve it into its record buffer.  No more than one record may match
    * the criteria.  Use the default substitution parameters and lock type.
    *
    * @throws  ErrorConditionException
    *          if an error occurred during record retrieval or if more than
    *          one record is found which match the criteria.
    * @throws  QueryOffEndException
    *          if no record could be found when operating in compound query
    *          mode.
    */
   public boolean unique()
   {
      boolean avail = getDelegate().unique();
      maybeFireCallback();
      
      return avail;
   }
   
   /**
    * Navigate to a particular record which meets the query criteria and
    * retrieve it into its record buffer.  No more than one record may match
    * the criteria.  Use the default substitution parameters, but override
    * the default lock type with that provided.
    *
    * @param   lockType
    *          Lock type to acquire for the retrieved record.
    *
    * @throws  ErrorConditionException
    *          if an error occurred during record retrieval or if more than
    *          one record is found which match the criteria.
    * @throws  QueryOffEndException
    *          if no record could be found when operating in compound query
    *          mode.
    */
   public boolean unique(LockType lockType)
   {
      boolean avail = getDelegate().unique(lockType);
      maybeFireCallback();
      
      return avail;
   }
   
   /**
    * Navigate to a particular record which meets the query criteria and
    * retrieve it into its record buffer.  No more than one record may match
    * the criteria.  Use the default lock type, but override the default
    * substitution parameters with those provided.
    * <p>
    * The delegate must be an instance of <code>RandomAccessQuery</code>
    *
    * @param   values
    *          Substitution values to use when issuing HQL queries.
    *
    * @throws  ErrorConditionException
    *          if an error occurred during record retrieval or if more than
    *          one record is found which match the criteria.
    * @throws  QueryOffEndException
    *          if no record could be found when operating in compound query
    *          mode.
    * @throws  IllegalStateException
    *          if delegate is not an instance of
    *          <code>RandomAccessQuery</code>.
    */
   public boolean unique(Object[] values)
   {
      return randomAccessDelegate().unique(values);
   }
   
   /**
    * Navigate to a particular record which meets the query criteria and
    * retrieve it into its record buffer.  No more than one record may match
    * the criteria.  Override both the default substitution parameters, and
    * the default lock type with those provided.
    * <p>
    * The delegate must be an instance of <code>RandomAccessQuery</code>
    *
    * @param   values
    *          Substitution values to use when issuing HQL queries.
    * @param   lockType
    *          Lock type to acquire for the retrieved record.
    *
    * @throws  ErrorConditionException
    *          if an error occurred during record retrieval or if more than
    *          one record is found which match the criteria.
    * @throws  QueryOffEndException
    *          if no record could be found when operating in compound query
    *          mode.
    * @throws  IllegalStateException
    *          if delegate is not an instance of
    *          <code>RandomAccessQuery</code>.
    */
   public boolean unique(Object[] values, LockType lockType)
   {
      return randomAccessDelegate().unique(values, lockType);
   }
   
   /**
    * Indicate whether a request to find the first result of this query would
    * succeed or fail.
    * <p>
    * Default substitution arguments and a lock type of <code>NONE</code> are
    * used for this test.
    * 
    * @return  <code>true</code> if the first record exists, else <code>false</code>.
    * 
    * @throws  UnsupportedOperationException
    *          always.
    */
   public logical hasAny()
   {
      throw new UnsupportedOperationException();
   }
   
   /**
    * Indicate whether a request to find the first result of this query would
    * succeed or fail.
    * <p>
    * The specified substitution arguments and a lock type of
    * <code>NONE</code> are used for this test.
    * 
    * @param   values
    *          Query substitution parameters.
    * 
    * @return  <code>true</code> if the first record exists, else <code>false</code>.
    * 
    * @throws  UnsupportedOperationException
    *          always.
    */
   public logical hasAny(Object[] values)
   {
      throw new UnsupportedOperationException();
   }
   
   /**
    * Indicate whether a request to find the first result of this query would
    * succeed or fail.
    * <p>
    * Default substitution arguments and the specified lock type are used for
    * this test.
    * 
    * @param   lockType
    *          Lock type for the query.  This lock is not actually acquired,
    *          only tested for availability.
    * 
    * @return  <code>true</code> if the first record exists, else <code>false</code>.
    * 
    * @throws  UnsupportedOperationException
    *          always.
    */
   public logical hasAny(LockType lockType)
   {
      throw new UnsupportedOperationException();
   }
   
   /**
    * Indicate whether a request to find the first result of this query would
    * succeed or fail.
    * <p>
    * The specified substitution arguments and lock type are used for this
    * test.
    *
    * @param   values
    *          Query substitution parameters.
    * @param   lockType
    *          Lock type for the query.  This lock is not actually acquired,
    *          only tested for availability.
    * 
    * @return  <code>true</code> if the first record exists, else <code>false</code>.
    * 
    * @throws  UnsupportedOperationException
    *          always.
    */
   public logical hasAny(Object[] values, LockType lockType)
   {
      throw new UnsupportedOperationException();
   }
   
   /**
    * Indicate whether this query would produce a unique result.
    * <p>
    * Default substitution arguments and a lock type of <code>NONE</code> are
    * used for this test.
    * 
    * @return  <code>true</code> if any record matching the query's criteria
    *          exists, else <code>false</code>.
    * 
    * @throws  UnsupportedOperationException
    *          always.
    */
   public logical hasOne()
   {
      throw new UnsupportedOperationException();
   }
   
   /**
    * Indicate whether this query would produce a unique result.
    * <p>
    * The specified substitution arguments and a lock type of
    * <code>NONE</code> are used for this test.
    * 
    * @param   values
    *          Query substitution parameters.
    * 
    * @return  <code>true</code> if any record matching the query's criteria
    *          exists, else <code>false</code>.
    * 
    * @throws  UnsupportedOperationException
    *          always.
    */
   public logical hasOne(Object[] values)
   {
      throw new UnsupportedOperationException();
   }
   
   /**
    * Indicate whether this query would produce a unique result.
    * <p>
    * Default substitution arguments and the specified lock type are used for
    * this test.
    * 
    * @param   lockType
    *          Lock type for the query.  This lock is not actually acquired,
    *          only tested for availability.
    * 
    * @return  <code>true</code> if any record matching the query's criteria
    *          exists, else <code>false</code>.
    * 
    * @throws  UnsupportedOperationException
    *          always.
    */
   public logical hasOne(LockType lockType)
   {
      throw new UnsupportedOperationException();
   }
   
   /**
    * Indicate whether this query would produce a unique result.
    * <p>
    * The specified substitution arguments and lock type are used for this
    * test.
    *
    * @param   values
    *          Query substitution parameters.
    * @param   lockType
    *          Lock type for the query.  This lock is not actually acquired,
    *          only tested for availability.
    * 
    * @return  <code>true</code> if any record matching the query's criteria
    *          exists, else <code>false</code>.
    * 
    * @throws  UnsupportedOperationException
    *          always.
    */
   public logical hasOne(Object[] values, LockType lockType)
   {
      throw new UnsupportedOperationException();
   }
   
   /**
    * Is this query set to fetch the next record after a reposition?
    *
    * @return  <code>true</code> if set to fetch after reposition, else
    *          <code>false</code>.
    */
   public boolean isFetchOnReposition()
   {
      return fetchOnReposition;
   }
   
   /**
    * Set this query to automatically fetch the next record after a
    * reposition, or turn this feature off.
    *
    * @param   enable
    *          <code>true</code> to enable automatic fetching;
    *          <code>false</code> to disable.
    */
   public void setFetchOnReposition(boolean enable)
   {
      fetchOnReposition = enable;
      if (delegate != null)
      {
         getDelegate().setFetchOnReposition(enable);
      }
   }
   
   /**
    * Adds a listener to be notified when this query is opened or closed.
    * <p> 
    * Note that this method is only called for dynamic queries only (for the moment).
    *
    * @param   listener
    *          The listener to be notified.
    */
   @Override
   public void addQueryEventListener(QueryEventListener listener)
   {
      // for the moment the QueryOpen notification only handles dynamic queries. The wrapper does
      // not notify about the event BUT will propagate the event to its [delegate] if any, and
      // that query will notify its listeners.
      if (delegate != null)
      {
         getDelegate().addQueryEventListener(listener);
      }
   }
   
   /**
    * Register a listener to receive notifications about the query has been opened.
    *
    * @param   listener
    *          The listener to be notified.
    */
   public void addOpenedListener(QueryOpenedListener listener)
   {
      openedListeners.add(listener);
   }
   
   /**
    * De-register a listener to receive notifications about the query has been opened.
    *
    * @param   listener
    *          The listener to be removed.
    */
   public void removeOpenedListener(QueryOpenedListener listener)
   {
      openedListeners.remove(listener);
   }
   
   /**
    * Register a listener to receive notifications reposition events for this
    * query.
    *
    * @param   listener
    *          Reposition listener to be registered.
    */
   public void addRepositionListener(RepositionListener listener)
   {
      repoListeners.add(listener);
      if (delegate != null)
      {
         getDelegate().addRepositionListener(listener);
      }
   }
   
   /**
    * Unregister a listener that was receiving notifications on reposition events for this
    * query.
    *
    * @param   listener
    *          Reposition listener to be unregistered.
    */
   public void removeRepositionListener(RepositionListener listener)
   {
      repoListeners.remove(listener);
      if (delegate != null)
      {
         getDelegate().removeRepositionListener(listener);
      }
   }

   /**
    * Sets an external result list handler and marks the query as browsed.
    *
    * @param resultListHandler
    *        External result list handler.
    */
   public void setBrowsed(ResultListHandler resultListHandler)
   {
      this.externalResultListHandler = resultListHandler;
      setBrowsed(resultListHandler != null);
   }
   
   /**
    * Indicate to this query that whether it is associated with a browse
    * widget or not.
    *
    * @param   browsed
    *          <code>true</code> to indicate the query has an associated
    *          browse widget, else <code>false</code>.
    */
   public void setBrowsed(boolean browsed)
   {
      this.browsed = browsed;
      if (!browsed)
      {
         externalResultListHandler = null;
      }
      
      if (delegate != null)
      {
         getDelegate().setBrowsed(browsed);
      }
   }
   
   /**
    * Is this query associated with a browse widget or not?
    *
    * @return  <code>true</code> if the query has an associated browse widget,
    */
   public boolean isBrowsed()
   {
      return browsed;
   }
   
   /**
    * Reposition the cursor such that a request to retrieve the next result
    * will retrieve the result which matches the specified primary key ID.  A
    * request to retrieve the previous result will retrieve the result
    * immediately previous to this, if any, in the results list.
    *
    * @param   id
    *          A primary key ID, representing the target record (in the case
    *          of a join, this ID is associated with the left-most record in
    *          the join).
    * 
    * @throws  ErrorConditionException
    *          if the specified ID represents the unknown value.
    */
   public void repositionByID(recid id)
   {
      if (!canReposition())
      {
         return;
      }
      
      getDelegate().repositionByID(id);
      maybeFireCallback();
   }
   
   /**
    * Reposition the cursor such that a request to retrieve the next result
    * will retrieve the result which matches the specified array of primary
    * key IDs.  A request to retrieve the previous result will retrieve the
    * result immediately previous to this, if any, in the results list.
    *
    * @param   id1
    *          A primary key ID, representing the target record (in the case
    *          of a join, this ID is associated with the left-most record in
    *          the join).
    * @param   joinIDs
    *          All remaining primary key IDs, if any, arranged from left to
    *          right to coincide with the records being joined by the
    *          underlying query.
    *
    *          If an array element is unknown, this element and all subsequent elements
    *          are ignored.
    *
    * @throws  ErrorConditionException
    *          if this query is not a scrolling query;
    *          if any of the specified IDs represents the unknown value.
    */
   public void repositionByID(rowid id1, rowid... joinIDs)
   {
      if (!canReposition())
      {
         return;
      }
      
      for(int i = 0; i < joinIDs.length; i++)
      {
         if(joinIDs[i].isUnknown())
         {
            rowid[] newIds = new rowid[i];
            System.arraycopy(joinIDs, 0, newIds, 0, i);
            joinIDs = newIds;
            break;
         }
      }
      
      getDelegate().repositionByID(id1, joinIDs);
      maybeFireCallback();
   }
   
   /**
    * Reposition the cursor such that a request to retrieve the next result will retrieve the
    * result which matches the specified array of primary key IDs. A request to retrieve the
    * previous result will retrieve the result immediately previous to this, if any, in the
    * results list.
    * <strong>Note:</strong> This is not public API.
    *
    * @param   joinIDs
    *          A set of primary key IDs, arranged from left to right to coincide with the records
    *          being joined by the underlying query.
    *
    * @throws  ErrorConditionException
    *          if any of the specified IDs represents the unknown value.
    *
    * @return  {@code true} on success.
    */
   @Override
   public boolean repositionByID(Long... joinIDs)
   {
      boolean ret = getDelegate().repositionByID(joinIDs);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Reposition the cursor to the specified row in the result set.  The row
    * indicates the position between two results, such that a call to
    * retrieve the next record will get the result at the specified row,
    * and a call to retrieve the previous result will get the result before
    * the new position.
    *
    * @param   row
    *          1-based index of the target position.
    *
    * @throws  ErrorConditionException
    *          if this query is not a scrolling query;
    *          if <code>row</code> represents unknown value.
    */
   public void reposition(NumberType row)
   {
      if (!canReposition())
      {
         return;
      }
      
      getDelegate().reposition(row);
      maybeFireCallback();
   }
   
   /**
    * Reposition the query to the specified row in the result set.  The row
    * indicates the position between two results, such that a call to
    * retrieve the next record will get the record after the new position,
    * and a call to retrieve the previous record will get the record before
    * the new position.
    *
    * @param   row
    *          1-based index of the target position.
    *
    * @throws  ErrorConditionException
    *          if this query is not a scrolling query.
    */
   public void reposition(int row)
   {
      /*
      WARNING: this is used internally, do not validate here
      if (!canReposition())
      {
         return;
      }
      */
      
      getDelegate().reposition(row);
      maybeFireCallback();
   }
   
   /**
    * Advance the current cursor position forward by the specified number of
    * rows.  This will always leave the cursor between two results.  For
    * example, given a request to move 1 row forward:
    * <ul>
    *   <li>if the cursor currently is positioned <i>directly on a result</i>,
    *       this would move it ahead <i>one and a half positions</i>, to just
    *       beyond the following result;
    *   <li>if the cursor currently is positioned <i>between two results</i>,
    *       this would move it ahead <i>one position</i>, to just beyond the
    *       following result.
    * </ul>
    *
    * @param   rows
    *          Number of rows to scroll the cursor forward.
    *
    * @return  {@code true} if operation was successful and the cursor was moved the exact amount
    *          of rows as specified by the parameter. If {@code false} is returned then it is
    *          possible that cursor's position was moved but not with {@code rows} rows.
    *
    * @throws  ErrorConditionException
    *          if this query is not a scrolling query;
    *          if <code>rows</code> represents the unknown value.
    */
   public boolean forward(NumberType rows)
   {
      if (!canReposition()) 
      {
         return false;
      }
      
      boolean ret = getDelegate().forward(rows);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Advance the current cursor position forward by the specified number of
    * rows.  This will always leave the cursor between two results.  For
    * example, given a request to move 1 row forward:
    * <ul>
    *   <li>if the cursor currently is positioned <i>directly on a result</i>,
    *       this would move it ahead <i>one and a half positions</i>, to just
    *       beyond the following result;
    *   <li>if the cursor currently is positioned <i>between two results</i>,
    *       this would move it ahead <i>one position</i>, to just beyond the
    *       following result.
    * </ul>
    *
    * @param   rows
    *          Number of rows to scroll the cursor forward.
    *
    * @return  {@code true} if operation was successful and the cursor was moved the exact amount
    *          of rows as specified by the parameter. If {@code false} is returned then it is
    *          possible that cursor's position was moved but not with {@code rows} rows.
    *
    * @throws  ErrorConditionException
    *          if this query is not a scrolling query.
    */
   public boolean forward(int rows)
   {
      if (!canReposition()) 
      {
         return false;
      }
      
      boolean ret = getDelegate().forward(rows);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Move the current cursor position backward by the specified number of
    * rows.  This will always leave the cursor between two results.  For
    * example, given a request to move 1 row backward:
    * <ul>
    *   <li>if the cursor currently is positioned <i>directly on a result</i>,
    *       this would move it back <i>one half position</i>, to just
    *       before the current result;
    *   <li>if the cursor currently is positioned <i>between two results</i>,
    *       this would move it back <i>one position</i>, to just before the
    *       current result.
    * </ul>
    *
    * @param   rows
    *          Number of rows to scroll the cursor backward.
    *
    * @return  {@code true} if operation was successful and the cursor was moved the exact amount
    *          of rows as specified by the parameter. If {@code false} is returned then it is
    *          possible that cursor's position was moved but not with {@code rows} rows.
    *
    * @throws  ErrorConditionException
    *          if this query is not a scrolling query;
    *          if <code>rows</code> represents the unknown value.
    */
   public boolean backward(NumberType rows)
   {
      if (!canReposition()) 
      {
         return false;
      }
      
      boolean ret = getDelegate().backward(rows);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Move the current cursor position backward by the specified number of
    * rows.  This will always leave the cursor between two results.  For
    * example, given a request to move 1 row backward:
    * <ul>
    *   <li>if the cursor currently is positioned <i>directly on a result</i>,
    *       this would move it back <i>one half position</i>, to just
    *       before the current result;
    *   <li>if the cursor currently is positioned <i>between two results</i>,
    *       this would move it back <i>one position</i>, to just before the
    *       current result.
    * </ul>
    *
    * @param   rows
    *          Number of rows to scroll the cursor backward.
    *
    * @return  {@code true} if operation was successful and the cursor was moved the exact amount
    *          of rows as specified by the parameter. If {@code false} is returned then it is
    *          possible that cursor's position was moved but not with {@code rows} rows.
    *
    * @throws  ErrorConditionException
    *          if this query is not a scrolling query.
    */
   public boolean backward(int rows)
   {
      if (!canReposition()) 
      {
         return false;
      }
      
      boolean ret = getDelegate().backward(rows);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Get the <b><i>current</i></b> size of the cached results list.  However,
    * since this cache is built progressively as the query is scrolled,
    * repositioned, and naturally navigated, this <b>does not</b> necessarily
    * represent the full count of results which may satisfy the query.
    *
    * @return  Current results list size or unknown value if the query is not
    *          open.
    *
    * @throws  ErrorConditionException
    *          if this query is not a scrolling query.
    */
   public integer size()
   {
      return getDelegate().size();
   }
   
   /** 
    * Get the recursive DATA-RELATION the query is to FILL for.  
    * @return the recursive DATA-RELATION the query is to FILL for
    */
   @Override
   public DataRelation getDataRelation() 
   {
      return this.relation;
   }
  
   /** 
    * Set the recursive DATA-RELATION the query is to FILL for.  
    * @param relation
    *       the recursive DATA-RELATION the query is to FILL for
    */
   @Override
   public void setDataRelation(final DataRelation relation) 
   {
      this.relation = relation;
      if (this.delegate != null && relation == null) 
      {
         this.delegate.setDataRelation(relation);
      }
   }
  
   /**
    * Progress-compatible function that returns the 1-based index of the
    * current row in the result set. This is the index of the entry at or
    * before which the cursor currently is positioned.
    *
    * @return  Unknown value if the query is not open or result set is empty.
    *          1 if the query is positioned before the first record.
    *          A value 1 greater than the number of rows in the query result
    *          set if the query is positioned beyond the last record.
    *          Otherwise returns the number of the current row in the query
    *          result set.
    */
   public integer currentRow()
   {
      return getDelegate().currentRow();
   }
   
   /**
    * Get the 1-based index of the current row in the result set.  This is
    * the index of the entry at or before which the cursor currently is
    * positioned.
    *
    * @return  Current row or the unknown value if the current row cannot be
    *          determined.  The current row cannot be determined if the
    *          results list is empty, or if the cursor currently is in
    *          backward scroll mode.
    *
    * @throws  ErrorConditionException
    *          if this query is not a scrolling query.
    */
   public integer currentRowImpl()
   {
      return getDelegate().currentRowImpl();
   }
   
   /**
    * Indicate whether the cursor has run off one or the other end of the
    * associated query's list of available results.  If <code>true</code>,
    * this indicates that the query cannot produce any more results in the
    * current scroll direction.
    *
    * @return  <code>true</code> if the cursor is off either end of its
    *          query's results list.
    *
    * @throws  ErrorConditionException
    *          if this query is not a scrolling query.
    */
   public logical isOffEnd()
   {
      return closed ? logical.UNKNOWN : getDelegate().isOffEnd();
   }
   
   /**
    * Indicate whether the cursor has run off one or the other end of the
    * associated query's list of available results.  If <code>true</code>,
    * this indicates that the query cannot produce any more results in the
    * current scroll direction.
    *
    * @return  <code>true</code> if the cursor is off either end of its
    *          query's results list.
    *
    * @throws  ErrorConditionException
    *          if this query is not a scrolling query.
    */
   public boolean _isOffEnd()
   {
      return getDelegate()._isOffEnd();
   }

   /**
    * Get the off-end status of the query, which indicates whether the query
    * has run off either end of its results.
    *
    * @return  One of the {@link OffEnd} constants <code>NONE</code>,
    *          <code>FRONT</code>, or <code>BACK</code>.
    */
   public OffEnd getOffEnd()
   {
      return getDelegate().getOffEnd();
   }

   /**
    * Determine whether the query result row currently being visited is the
    * first row in the presorted results list.
    * <p>
    * The delegate must be an instance of <code>PresortDelegate</code>
    *
    * @return  <code>true</code> if the current result row is the first row,
    *          else <code>false</code>.
    *
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>PresortDelegate</code>.
    */
   public logical isFirst()
   {
      return presortDelegate().isFirst();
   }
   
   /**
    * Determine whether the query result row currently being visited is the
    * first row within a break group whose category is identified by the
    * specified resolvable object.
    * <p>
    * The delegate must be an instance of <code>PresortDelegate</code>
    *
    * @param   key
    *          Break group category key.  Must be the same object reference
    *          as was specified previously when invoking one of the
    *          <code>addSortCriterion</code> method variants.
    *
    * @return  <code>true</code> if current row is first in a break group;
    *          <code>false</code> if it is not;  unknown value if break groups
    *          have not been enabled.
    *
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>PresortDelegate</code>.
    */
   public logical isFirstOfGroup(Resolvable key)
   {
      return presortDelegate().isFirstOfGroup(key);
   }
   
   /**
    * Determine whether the query result row currently being visited is the first row of the
    * query's result set or the first row within a break group whose category is identified by
    * the specified BREAK-BY level.
    *
    * @param   level
    *          Break group level, where 0 is the whole query, 1 is the first BREAK-BY sort
    *          criterion, etc. Must not be negative or greater than the number of sort criteria.
    *          Must not be unknown value.
    *
    * @return  {@code true} if the current row is first in the result set or within the specified
    *          break group; else {@code false}.
    */
   public logical isFirstOfGroup(integer level)
   {
      return presortDelegate().isFirstOfGroup(level);
   }
   
   /**
    * Determine whether the query result row currently being visited is the first row of the
    * query's result set or the first row within a break group whose category is identified by
    * the specified BREAK-BY level.
    *
    * @param   level
    *          Break group level, where 0 is the whole query, 1 is the first BREAK-BY sort
    *          criterion, etc. Must not be negative or greater than the number of sort criteria.
    *
    * @return  {@code true} if the current row is first in the result set or within the specified
    *          break group; else {@code false}.
    */
   public logical isFirstOfGroup(int level)
   {
      return isFirstOfGroup(new integer(level));
   }
   
   /**
    * Determine whether the query result row currently being visited is the
    * last row in the presorted results list.
    * <p>
    * The delegate must be an instance of <code>PresortDelegate</code>
    *
    * @return  <code>true</code> if the current result row is the last row,
    *          else <code>false</code>.
    *
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>PresortDelegate</code>.
    */
   public logical isLast()
   {
      return presortDelegate().isLast();
   }
   
   /**
    * Determine whether the query result row currently being visited is the
    * first row within a break group whose category is identified by the
    * specified resolvable object.
    * <p>
    * The delegate must be an instance of <code>PresortDelegate</code>
    *
    * @param   key
    *          Break group category key.  Must be the same object reference
    *          as was specified previously when invoking one of the
    *          <code>addSortCriterion</code> method variants.
    *
    * @return  <code>true</code> if current row is first in a break group;
    *          <code>false</code> if it is not;  unknown value if break groups
    *          have not been enabled.
    *
    * @throws  IllegalStateException
    *          if delegate is not an instance of <code>PresortDelegate</code>.
    */
   public logical isLastOfGroup(Resolvable key)
   {
      return presortDelegate().isLastOfGroup(key);
   }
   
   /**
    * Determine whether the query result row currently being visited is the last row of the
    * query's result set or the last row within a break group whose category is identified by
    * the specified BREAK-BY level.
    *
    * @param   level
    *          Break group level, where 0 is the whole query, 1 is the first BREAK-BY sort
    *          criterion, etc. Must not be negative or greater than the number of sort criteria.
    *          Must not be unknown value.
    *
    * @return  {@code true} if the current row is last in the result set or within the specified
    *          break group; else {@code false}.
    */
   public logical isLastOfGroup(integer level)
   {
      return presortDelegate().isLastOfGroup(level);
   }
   
   /**
    * Determine whether the query result row currently being visited is the last row of the
    * query's result set or the last row within a break group whose category is identified by
    * the specified BREAK-BY level.
    *
    * @param   level
    *          Break group level, where 0 is the whole query, 1 is the first BREAK-BY sort
    *          criterion, etc. Must not be negative or greater than the number of sort criteria.
    *
    * @return  {@code true} if the current row is last in the result set or within the specified
    *          break group; else {@code false}.
    */
   public logical isLastOfGroup(int level)
   {
      return isLastOfGroup(new integer(level));
   }
   
   /**
    * Indicate whether this query preselects all of its results.
    *
    * @return  <code>true</code> if the query preselects its results;
    *          <code>false</code> if the query's results are dynamically
    *          navigated.
    */
   public boolean isPreselect()
   {
      return getDelegate().isPreselect();
   }
   
   /**
    * Indicate whether this query is a preselect query by its nature.
    *
    * @return  <code>true</code>.
    */
   public boolean isNativelyPreselect()
   {
      return getDelegate().isNativelyPreselect();
   }
   
   /**
    * Notify all registered listeners that query is repositioned or closed.
    * 
    * @param   closed
    *          A <code>true</code> value will inform all listeners that the
    *          query was explicitly closed.
    * @param   error
    *          <code>true</code> if an error happened during reposition.
    * @param   targetRepositionRow
    *          Row used as the target for reposition. If it was deleted, reposition with fetching
    *          may end up on a different row.
    */
   public void notifyRepositionListeners(boolean closed, boolean error, int targetRepositionRow)
   {
      delegate.notifyRepositionListeners(closed, error, targetRepositionRow);
   }
   
   /**
    * Notify all registered listeners that query is repositioned in case if
    * query is attached to browse widget.
    * 
    * @deprecated Use #open() instead.
    */
   @Deprecated
   public void notifyListeners()
   {
      open();
   }
   
   /**
    * Indicate whether this query stands alone, or is the component of
    * another query, or is wrapped by a query wrapper.
    * 
    * @return  <code>true</code>;  query wrappers may not themselves be
    *          wrapped.
    */
   public boolean isStandalone()
   {
      return true;
   }
   
   /**
    * Change the standalone nature of this query.  A query is standalone by
    * default, but can be changed to non-standalone by the wrapper or
    * container which contains it.
    * <p>
    * Instances of <code>QueryWrapper</code> may not be wrapped in other
    * queries or query wrappers, so this implementation throws an exception
    * if this method is invoked with a parameter of <code>true</code>.
    * 
    * @param   standalone
    *          <code>true</code> to set query as standalone;
    *          <code>false</code> to set query as contained.
    *
    * @throws  UnsupportedOperationException
    *          if <code>standalone</code> is set to <code>true</code>.
    */
   public void setStandalone(boolean standalone)
   {
      if (!standalone)
      {
         throw new UnsupportedOperationException(
            "Query wrapper must be standalone");
      }
   }
   
   /**
    * Delegate cleanup processing to the query wrapped by this object.
    * 
    * @see  P2JQuery#cleanup()
    */
   public void cleanup()
   {
      if (!closed)
      {
         delegate.cleanup();
      }
   }

   /**
    * Generate a handle to the query object.
    *
    * Returns a handle of a query object.
    *
    * @return query handle
    */
   public handle asHandle()
   {
      return new handle(this);
   }

   /**
    * Conversion of GET-BUFFER-HANDLE() method (KW_GET_BUFH).
    *
    * Returns a handle of the first buffer of a query object.
    *
    * @return buffer handle
    */
   public handle bufferHandle()
   {
      return bufferHandle(1);
   }

   /**
    * Conversion of GET-BUFFER-HANDLE() method (KW_GET_BUFH).
    *
    * Returns a handle of the first buffer of a query object.
    *
    * @return buffer handle
    */
   public Buffer bufferHandleNative()
   {
      return getBufferByIndex(1);
   }

   /**
    * Conversion of GET-BUFFER-HANDLE() method (KW_GET_BUFH).
    *
    * Returns a handle of a particular buffer of a query object.
    *
    * @param   bufferName
    *          buffer-name. A CHARACTER expression that evaluates to the name
    *          of a buffer in the query or DataSet object.
    *
    * @return buffer handle
    */
   public handle bufferHandle(String bufferName)
   {
      return bufferHandle(new character(bufferName));
   }

   /**
    * Conversion of GET-BUFFER-HANDLE() method (KW_GET_BUFH).
    *
    * Returns a handle of a particular buffer of a query object.
    *
    * @param   bufferName
    *          buffer-name. A CHARACTER expression that evaluates to the name
    *          of a buffer in the query or DataSet object.
    *
    * @return buffer handle
    */
   public handle bufferHandle(character bufferName)
   {
      for (int i = 0; i < buffers.size(); i++)
      {
         Buffer buf = buffers.get(i);
         if (CompareOps._isEqual(bufferName, buf.name()))
         {
            handle h = new handle();
            h.assign(buf);
            return h;
         }
      }
      
      String errMsg = "Query method argument must be the name of a query buffer or an integer " +
                      "from 1 to %d for query %s";
      errMsg = String.format(errMsg, numBuffers().intValue(), qname);
      
      ErrorManager.recordOrShowDatabaseError(7361, errMsg, false, false);
      
      return new handle();
   }

   /**
    * Conversion of GET-BUFFER-HANDLE() method (KW_GET_BUFH).
    *
    * Returns a handle of a particular buffer of a query object.
    *
    * @param   bufferSequenceNumber
    *          buffer-sequence-number. An INTEGER that represents the sequence
    *          number of the desired buffer.
    *
    * @return buffer handle
    */
   public handle bufferHandle(int bufferSequenceNumber)
   {
      return bufferHandle(new integer(bufferSequenceNumber));
   }

   /**
    * Conversion of GET-BUFFER-HANDLE() method (KW_GET_BUFH).
    *
    * Returns a handle of a particular buffer of a query object.
    *
    * @param   bufferSequenceNumber
    *          buffer-sequence-number. An INTEGER that represents the sequence
    *          number of the desired buffer.
    *
    * @return buffer handle
    */
   @Override
   public handle bufferHandle(int64 bufferSequenceNumber)
   {
      int idx = bufferSequenceNumber.isUnknown() ? 0 : bufferSequenceNumber.intValue();
      return new handle(getBufferByIndex(idx));
   }

   /**
    * Conversion of GET-BUFFER-HANDLE() method (KW_GET_BUFH).
    *
    * Returns a particular buffer of a query object.
    *
    * @param   bufferSequenceNumber
    *          buffer-sequence-number. An INTEGER that represents the sequence
    *          number of the desired buffer.
    *
    * @return buffer object
    */
   public Buffer getBufferByIndex(int bufferSequenceNumber)
   {
      if (bufferSequenceNumber >= 1 && bufferSequenceNumber <= buffers.size())
      {
         return buffers.get(bufferSequenceNumber - 1);
      }

      String errMsg = "Query method argument must be the name of a query buffer or an integer " +
         "from 1 to %d for query %s";
      errMsg = String.format(errMsg, numBuffers().intValue(), qname);

      ErrorManager.recordOrShowDatabaseError(7361, errMsg, false, false);

      return null;
   }

   /**
    * Conversion of QUERY-CLOSE() method (KW_QRY_CLOS).
    *
    * Closes a query object.
    *
    * @return  <code>true</code> if QUERY-CLOSE() succeeds,
    *          else <code>false</code>.
    */
   public logical queryClose()
   {
      boolean success = true;

      if (delegate != null)
      {
         delegate.notifyQueryCloseListeners();
      }
      
      try
      {
         close();
      }
      catch (ErrorConditionException exc)
      {
         success = false;
      }

      return logical.of(success);
   }

   /**
    * Conversion of REPOSITION-BACKWARD() method (KW_REPOS_B).
    *
    * Moves a query object's result list pointer backward a particular number
    * of rows.
    *
    * @return  <code>true</code> if REPOSITION-BACKWARD() succeeds,
    *          else <code>false</code>.
    */
   public logical queryBackward(int rows)
   {
      return queryBackward(new integer(rows));
   }
   
   /**
    * Conversion of REPOSITION-BACKWARD() method (KW_REPOS_B).
    *
    * Moves a query object's result list pointer backward a particular number
    * of rows.
    *
    * @return  {@code true} if operation was successful and the cursor was moved the exact amount
    *          of rows as specified by the parameter. If {@code false} is returned then it is
    *          possible that cursor's position was moved but not with {@code rows} rows.
    */
   public logical queryBackward(NumberType rows)
   {
      if (rows.isUnknown())
      {
         // TODO: what error should be shown?
         return logical.of(false);
      }
      
      try
      {
         return logical.of(backward(rows));
      }
      catch (ErrorConditionException exc)
      {
         return logical.of(false);
      }
   }
   
   /**
    * Conversion of REPOSITION-FORWARD() method (KW_REPOS_F).
    *
    * Moves a query object's result list pointer forward a particular number
    * of rows.
    *
    * @return  <code>true</code> if REPOSITION-FORWARD() succeeds,
    *          else <code>false</code>.
    */
   public logical queryForward(int rows)
   {
      return queryForward(new integer(rows));
   }
   
   /**
    * Conversion of REPOSITION-FORWARD() method (KW_REPOS_F).
    *
    * Moves a query object's result list pointer forward a particular number
    * of rows.
    *
    * @return  {@code true} if operation was successful and the cursor was moved the exact amount
    *          of rows as specified by the parameter. If {@code false} is returned then it is
    *          possible that cursor's position was moved but not with {@code rows} rows.
    */
   public logical queryForward(NumberType rows)
   {
      if (rows.isUnknown())
      {
         // TODO: what error should be shown?
         return logical.of(false);
      }
      
      try
      {
         return logical.of(forward(rows));
      }
      catch (ErrorConditionException exc)
      {
         return logical.of(false);
      }
   }
   
   /**
    * Conversion of REPOSITION-TO-ROW() method (KW_REPOS_2R).
    *
    * Moves a query object's result list pointer to the row corresponding to the specified
    * sequence number.
    *
    * @param   n
    *          An integer expression representing the sequence number.
    *
    * @return  <code>true</code> if REPOSITION-TO-ROW() succeeds,
    *          else <code>false</code>.
    */
   public logical queryReposition(int n)
   {
      return queryReposition(new integer(n));
   }

   /**
    * Conversion of REPOSITION-TO-ROW() method (KW_REPOS_2R).
    *
    * Moves a query object's result list pointer to the row corresponding to the specified
    * sequence number.
    *
    * @param   n
    *          An integer expression representing the sequence number.
    *
    * @return  <code>true</code> if REPOSITION-TO-ROW() succeeds,
    *          else <code>false</code>.
    */
   public logical queryReposition(NumberType n)
   {
      boolean success = true;

      try
      {
         reposition(n);
      }
      catch (ErrorConditionException exc)
      {
         success = false;
      }

      return logical.of(success);
   }

   /**
    * Conversion of REPOSITION-TO-ROWID() method (KW_REPOS_2I).
    *
    * Reposition the cursor such that a request to retrieve the next result
    * will retrieve the result which matches the specified array of primary
    * key IDs.  A request to retrieve the previous result will retrieve the
    * result immediately previous to this, if any, in the results list.
    *
    * @param   id1
    *          A primary key ID, representing the target record (in the case
    *          of a join, this ID is associated with the left-most record in
    *          the join).
    * @param   joinIDs
    *          All remaining primary key IDs, if any, arranged from left to
    *          right to coincide with the records being joined by the
    *          underlying query.
    *
    * @return  <code>true</code> if REPOSITION-TO-ROWID() succeeds,
    *          else <code>false</code>.
    */
   public logical queryRepositionByID(rowid id1, rowid...joinIDs)
   {
      boolean success = true;

      try
      {
         repositionByID(id1, joinIDs);
      }
      catch (ErrorConditionException exc)
      {
         success = false;
      }
      
      return logical.of(success);
   }
   
   /**
    * Conversion of REPOSITION-TO-ROWID() method (KW_REPOS_2I).
    *
    * Reposition the cursor such that a request to retrieve the next result
    * will retrieve the result which matches the specified array of primary
    * key IDs.  A request to retrieve the previous result will retrieve the
    * result immediately previous to this, if any, in the results list.
    *
    * @param   id1
    *          A primary key ID, representing the target record (in the case
    *          of a join, this ID is associated with the left-most record in
    *          the join).
    * @param   joinIDs
    *          The list of IDs, starting with the primary key ID representing the target record, while 
    *          all remaining primary key IDs, if any, arranged from left to right to coincide with the records 
    *          being joined by the underlying query.
    *
    * @return  <code>true</code> if REPOSITION-TO-ROWID() succeeds,
    *          else <code>false</code>.
    */
   @Override
   public logical queryRepositionByID(rowid[] joinIDs)
   {
      if (joinIDs.length == 1)
      {
         return queryRepositionByID(joinIDs[0]);
      }
      else if (joinIDs.length == 0)
      {
         return logical.FALSE;
      }
      else
      {
         rowid[] r = new rowid[joinIDs.length - 1];
         System.arraycopy(joinIDs, 1, r, 0, r.length);
         return queryRepositionByID(joinIDs[0], r);
      }
   }

   /**
    * Conversion of REPOSITION-TO-ROWID() method (KW_REPOS_2I).
    *
    * Reposition the cursor such that a request to retrieve the next result
    * will retrieve the result which matches the specified array of primary
    * key IDs.  A request to retrieve the previous result will retrieve the
    * result immediately previous to this, if any, in the results list.
    *
    * @param   rowId
    *          A character representation of this rowid.
    *
    * @return  <code>true</code> if REPOSITION-TO-ROWID() succeeds,
    *          else <code>false</code>.
    */
   public logical queryRepositionByID(character rowId)
   {
      UnimplementedFeature.missing("QUERY:REPOSITION-BY-ID(character)");
      return logical.UNKNOWN;
   }

   /**
    * Conversion of NUM-RESULTS attribute (KW_NUM_RES).
    * 
    * Getter of NUM-RESULTS attribute
    * 
    * @return  Number of rows currently in the results list of a scrolling query. If the query
    *          is not open or it is not scrolling, returns the unknown value.
    */
   public integer getNumResults()
   {
      P2JQuery delegate = getDelegate();
      
      if (!delegate.isScrolling() || (prepareString != null && closed))
      {
         return new integer();
      }
      
      try
      {
         return delegate.size();
      }
      catch (UnsupportedOperationException e)
      {
         return new integer();
      }
   }
   
   /**
    * Adds one new buffer to a query object or dynamic DataSet object,
    * without affecting the other buffers, if any. Use the SET-BUFFERS( )
    * method to remove all prior buffers and set all buffers for the object
    * at the same time.
    *
    * @param   bufHandle
    *          A buffer handle to add.
    *
    * @return  true on success
    */
   public logical addBuffer(handle bufHandle)
   {
      if (!canAddBuffer() || !validBuffer(bufHandle, 1))
      {
         return logical.of(false);
      }
      
      if (!closed)
      {
         close();
      }
      
      Buffer buf = (Buffer) bufHandle.get();
      return addBuffer(buf);
   }
   
   /**
    * Adds one new buffer to a query object or dynamic DataSet object,
    * without affecting the other buffers, if any. Use the SET-BUFFERS( )
    * method to remove all prior buffers and set all buffers for the object
    * at the same time.
    *
    * @param   buf
    *          A buffer to add.
    *
    * @return  true on success
    */
   @Override
   public logical addBuffer(Buffer buf)
   {
      return addBuffer(buf, false);
   }
   
   /**
    * Adds one new buffer to a query object or dynamic DataSet object,
    * without affecting the other buffers, if any. Use the SET-BUFFERS( )
    * method to remove all prior buffers and set all buffers for the object
    * at the same time.
    *
    * @param   bufName
    *          A buffer name use to identify a buffer to be added.
    *
    * @return  true on success
    */
   @Override
   public logical addBuffer(character bufName)
   {
      return addBuffer(bufName.toStringMessage());
   }
   
   /**
    * Adds one new buffer to a query object or dynamic DataSet object,
    * without affecting the other buffers, if any. Use the SET-BUFFERS( )
    * method to remove all prior buffers and set all buffers for the object
    * at the same time.
    *
    * @param   bufName
    *          A buffer name use to identify a buffer to be added.
    *
    * @return  true on success
    */
   @Override
   public logical addBuffer(String bufName)
   {
      if (!canAddBuffer())
      {
         return logical.of(false);
      }
      
      Buffer crtBuff = parseBuffer(BufferManager.get(), bufName, 1);
      if (crtBuff == null)
      {
         return logical.of(false);
      }
      
      return addBuffer(crtBuff);
   }
   
   /**
    * Adds one new buffer to a query object or dynamic DataSet object, 
    * without affecting the other buffers, if any. Use the SET-BUFFERS( )
    * method to remove all prior buffers and set all buffers for the object 
    * at the same time.
    * 
    * @param   buf
    *          A buffer to add.
    * @param   staticCall
    *          <code>true</code> if it is internal call for a static query.
    *
    * @return  true on success
    */
   public logical addBuffer(Buffer buf, boolean staticCall)
   {
      if (!staticCall)
      {
         if (!canAddBuffer())
         {
            return logical.of(false);
         }
         
         if (!closed)
         {
            close();
         }
         
         // reset the prepare-string
         prepareString = null;
      }
      else if (!dynamic && !cleanerRegistered)
      {
         registerCleaner();
      }
      
      // if the buffer already exists, is added anyway
      this.buffers.add(((BufferImpl) buf).ref());
      ((BufferImpl) buf).setQuery(this);
      
      RecordBuffer recordBuffer = ((BufferImpl) buf).buffer();
      recordBuffer.registerRelatedQuery(this);
      
      return logical.of(true);
   }
   
   /**
    * Sets buffers for the query. Any buffers previously added
    * or set are removed. Use the <code>addBuffer()</code> method to add one 
    * buffer to the object, without affecting the other buffers, if any.
    * This method is the equivalent of <code>SET-BUFFERS()</code> method 
    * from 4GL.
    *
    * @param   hBuffers
    *          Variable argument list of buffer handles to be set.
    *          In 4GL, the maximum number of buffers per query is 18.
    * 
    * @return  true on success
    */
   @Override
   public logical setBuffers(handle... hBuffers)
   {
      if (!canAddBuffer())
      {
         return logical.of(false);
      }
      
      // validate all handles upfront
      for (int i = 0; i < hBuffers.length; i++)
      {
         if (!validBuffer(hBuffers[i], i + 1))
         {
            return logical.of(false);
         }
      }
      
      if (!closed)
      {
         close();
      }
      
      resetQuery();
      
      for (handle h : hBuffers)
      {
         addBuffer((Buffer) h.get());
      }
      
      return logical.of(true);
   }
   
   /**
    * Sets buffers for the query. Any buffers previously added
    * or set are removed. Use the <code>addBuffer()</code> method to add one 
    * buffer to the object, without affecting the other buffers, if any.
    * This method is the equivalent of <code>SET-BUFFERS()</code> method 
    * from 4GL.
    * 
    * @param   bufs
    *          Variable argument list of Buffer to be set.
    *          In 4GL, the maximum number of buffers per query is 18.
    * 
    * @return  true on success
    */
   @Override
   public logical setBuffers(Buffer... bufs)
   {
      if (!canAddBuffer())
      {
         return logical.of(false);
      }
      
      if (!closed)
      {
         close();
      }
      
      resetQuery();
      
      for (Buffer buf : bufs)
      {
         addBuffer(buf);
      }
      
      return logical.of(true);
   }
   
   /**
    * Sets buffers for the query. Any buffers previously added
    * or set are removed. Use the <code>addBuffer()</code> method to add one 
    * buffer to the object, without affecting the other buffers, if any.
    * This method is the equivalent of <code>SET-BUFFERS()</code> method 
    * from 4GL.
    * 
    * @param   bufs
    *          Variable argument list of Buffer to be set.
    *          In 4GL, the maximum number of buffers per query is 18.
    * 
    * @return  true on success
    */
   @Override
   public logical setBuffers(Object... bufs)
   {
      if (!canAddBuffer())
      {
         return logical.of(false);
      }
      
      if (!closed)
      {
         close();
      }
      
      resetQuery();
      
      BufferManager bm = null;
      ArrayList<Buffer> localBuffers = new ArrayList<>(bufs.length);
      for (int i = 0; i < bufs.length; i++)
      {
         Buffer crtBuff = null;
         if (bufs[i] instanceof Buffer)
         {
            crtBuff = (Buffer) bufs[i]; 
         }
         else if (bufs[i] instanceof handle)
         {
            handle asHandle = (handle) bufs[i]; 
            // references must be valid:
            if (asHandle.isUnknown() || !asHandle.isType(LegacyResource.BUFFER))
            {
               ErrorManager.recordOrShowError(7319, Integer.toString(i + 1));
               // ADD/SET-BUFFERS argument <argnumber> was invalid or not found.
               return logical.of(false);
            }
            crtBuff = (Buffer) asHandle.get();
         }
         else if (bufs[i] instanceof character || bufs[i] instanceof String)
         {
            if (bm == null)
            {
               bm = BufferManager.get();
            }
            String name = (bufs[i] instanceof String)
                     ? (String) bufs[i] : ((character) bufs[i]).toStringMessage();
            crtBuff = parseBuffer(bm, name, i + 1);
            if (crtBuff == null)
            {
               return logical.of(false);
            }
         }
         else
         {
            // unknown/invalid data type
            ErrorManager.recordOrShowError(7319, Integer.toString(i + 1));
            // ADD/SET-BUFFERS argument <arg-number> was invalid or not found.
            return logical.of(false);
         }
         
         localBuffers.add(crtBuff);
      }
      
      for (int i = 0; i < localBuffers.size(); i++)
      {
         Buffer buffer = localBuffers.get(i);
         addBuffer(buffer);
      }
      
      return logical.of(true);
   }
   
   /**
    * Compiles a predicate (query condition). The query must be open after this call.
    * This method is the equivalent of {@code QUERY-PREPARE()} method from 4GL.
    *  
    * @param   predicate
    *          The predicate to be prepared by this query. The syntax of the string is the same
    *          of the {@code OPEN QUERY} statement of the 4GL.
    * 
    * @return  true on success
    */
   @Override
   public logical prepare(String predicate)
   {
      return prepare(new character(predicate));
   }
   
   /**
    * Compiles a predicate (query condition). The query must be open after this call.
    * This method is the equivalent of <code>QUERY-PREPARE()</code> method from 4GL.
    *  
    * @param   predicate
    *          The predicate to be prepared by this query. The syntax of the string is the same
    *          of the <code>OPEN QUERY</code> statement of the 4GL.
    * 
    * @return  true on success
    */
   @Override
   public logical prepare(character predicate)
   {
      // validate first
      if (predicate.isUnknown())
      {
         final String errMsg = 
            "QUERY-PREPARE requires a valid non-null character argument for query %s";
         
         ErrorManager.recordOrShowDatabaseError(7321, String.format(errMsg, qname), false, false);
         
         return logical.of(false);
      }
      if (buffers.isEmpty())
      {
         final String errMsg = 
            "QUERY-PREPARE requires that SET-BUFFERS has been used to assign buffers to query %s";
         
         ErrorManager.recordOrShowDatabaseError(7322, String.format(errMsg, qname), false, false);
         
         return logical.of(false);
      }
      
      // close the query, if opened
      close();
      
      // reset vars
      prepareString = null;
      dynamicDelegate = false;
      
      // parse the predicate and instantiate a new delegate
      String qprepare = predicate.toStringMessage();
      P2JQuery query = DynamicQueryHelper.parseQuery(buffers, qprepare, qname, substBuffers);
      
      if (query != null)
      {
         this.dynamicDelegate = true;
         this.prepareString = qprepare;
         query.setDynamicPredicate(true);
         assignImpl(query, false);
      }
      
      return logical.of(query != null);
   }
   
   /**
    * Opens a query object.
    * This method is the equivalent of <code>QUERY-OPEN()</code> method from 4GL.
    * <u>Note</u>: You must perform <code>prepare()</code> on a query 
    * object before you perform <code>queryOpen</code> on it. 
    * 
    * @return  true on success
    */
   @Override
   public logical queryOpen()
   {
      String errMsg = "QUERY-OPEN for query %s requires a previous QUERY-PREPARE";
      
      if (prepareString == null)
      {
         ErrorManager.recordOrShowDatabaseError(7312, String.format(errMsg, qname), true, false);
         return logical.of(false);
      }
      
      if (!closed)
      {
         close();
      }
      
      // call onOpen() if needed.
      if (delegate != null)
      {
         delegate.setDataRelation(this.relation);
         delegate.notifyQueryOpenListeners(true);
      }
      
      try
      {
         open();
      }
      catch (ErrorConditionException ece)
      {
         close();
         ErrorManager.recordOrShowDatabaseError(7312, String.format(errMsg, ""), true, false);
         return logical.of(false);
      }
      
      // make one time deferred reposition for registered listeners if required
      for (int i = 0; i < openedListeners.size(); i++)
      {
         QueryOpenedListener listener = openedListeners.get(i);
         listener.afterQueryOpen();
      }
      
      return logical.of(true);
   }
   
   /**
    * Conversion of INDEX-INFORMATION attribute (KW_IDX_INFO).
    *
    * Getter of INDEX-INFORMATION attribute
    *
    * @return A character string consisting of a comma-separated list of the index or
    *         indexes the query uses at the level of join specified.
    */
   public character indexInformation()
   {
      return indexInformation(new integer(1));
   }

   /**
    * Conversion of INDEX-INFORMATION attribute (KW_IDX_INFO).
    *
    * Getter of INDEX-INFORMATION attribute
    *
    * @param n
    * An integer expression that evaluates to the level of join for which you want
    * index information.

    * @return A character string consisting of a comma-separated list of the index or
    *         indexes the query uses at the level of join specified.
    */
   public character indexInformation(int n)
   {
      return indexInformation(new integer(n));
   }

   /**
    * Conversion of INDEX-INFORMATION attribute (KW_IDX_INFO).
    *
    * Getter of INDEX-INFORMATION attribute
    *
    * @param    n
    *           An integer expression that evaluates to the level of join for which you want index
    *           information.
    *
    * @return   A character string consisting of a comma-separated list of the index or
    *           indexes the query uses at the level of join specified.
    */
   public character indexInformation(NumberType n)
   {
      if (delegate != null && delegate != DEFAULT_DELEGATE)
      {
         if (this.closed)
         {
            getDelegate().notifyQueryOpenListeners(false);
         }
      }
      else
      {
         ErrorManager.recordOrShowDatabaseError(
                  7362, 
                  "INDEX-INFORMATION requires query " + qname + 
                  " to be QUERY-PREPARED or open and defined with RCODE-INFORMATION", 
                  true, false
         );
         return new character();
      }

      int val = n.intValue();
      int tableCount = getDelegate().getTableCount();

      if (val < 1 || val > tableCount)
      {
         ErrorManager.recordOrShowError(7361,
               String.format("Query method argument must be the name of a query buffer or an " +
                                "integer from 1 to %d for query %s",
                             tableCount,
                             name == null ? "?" : name),
                             false,
                             false);
         return new character();
      }

      character res = getDelegate().indexInformation(n);
      if (res.isUnknown())
      {
         res.assign(IndexHelper.WHOLE_INDEX_PREFIX + "default");
      }

      return res;
   }

   /**
    * Conversion of FORWARD-ONLY attribute (KW_FWD_ONLY).
    *
    * Getter of FORWARD-ONLY attribute.
    *
    * @return current value of FORWARD-ONLY attribute.
    */
   public logical forwardOnly()
   {
      return logical.of(forwardOnly);
   }

   /**
    * Conversion of FORWARD-ONLY attribute (KW_FWD_ONLY).
    *
    * Setter of FORWARD-ONLY attribute.
    *
    * @param  forwardOnly
    *         New value of FORWARD-ONLY attribute.
    */
   public void changeForwardOnly(logical forwardOnly)
   {
      if (forwardOnly.isUnknown())
      {
         final String errMsg = "Unable to assign UNKNOWN value to attribute FORWARD-ONLY on QUERY widget";
         
         // this does not exhitibit 'database behavior' related to throwing structured exceptions 
         // - see recordOrShowDatabaseError'
         ErrorManager.recordOrShowError(4083, errMsg, false, true, false);
         
         return;
      }
      
      if (!closed || browsed)
      {
         String msg1 = "Forward only status may not be changed while query %s is open or being browsed";
         msg1 = String.format(msg1, qname);
         final String msg2 = "Unable to set attribute FORWARD-ONLY in widget  of type QUERY";
         
         ErrorManager.recordOrShowError(new int[] { 12354, 3131 },
                                        new String[] { msg1, msg2 }, 
                                        false, false, true);
         
         return;
      }
      
      setForwardOnly(forwardOnly.booleanValue());
   }
   
   /**
    * Set the forward-only attribute for all delegate queries assigned to this wrapper.
    *
    * @param   value
    *          <code>true</code> to enable forward-only, <code>false</code> to disable it.
    */
   public void setForwardOnly(boolean value)
   {
      forwardOnly = value;
      if (delegate != null)
      {
         getDelegate().setForwardOnly(value);
      }
   }
   
   /**
    * Method that returns the value of the forwardOnly flag.
    * 
    * @return  <code>true</code> if forward-only is enabled, <code>false</code> otherwise.
    */
   public boolean isForwardOnly()
   {
      return forwardOnly;
   }

   /**
    * Conversion of FORWARD-ONLY attribute (KW_FWD_ONLY).
    *
    * Setter of FORWARD-ONLY attribute.
    *
    * @param  forwardOnly
    *         New value of FORWARD-ONLY attribute.
    */
   public void changeForwardOnly(boolean forwardOnly)
   {
      changeForwardOnly(logical.of(forwardOnly));
   }

   /**
    * Conversion of PREPARE_STRING attribute (KW_PREP_STR).
    *
    * Getter of PREPARE_STRING attribute.
    *
    * @return current value of PREPARE_STRING attribute.
    */
   public character prepareString()
   {
      return new character(prepareString);
   }

   /**
    * Getter for the CACHE attribute.
    * 
    * @return   See above.
    */
   @Override
   public integer getCache()
   {
      UnimplementedFeature.missing("QUERY:CACHE");
      return new integer();
   }
   
   /**
    * Setter for the CACHE attribute.
    * 
    * @param    n
    *           The cache value.
    */
   @Override
   public void setCache(integer n)
   {
      UnimplementedFeature.missing("QUERY:CACHE");
   }
   
   /**
    * Setter for the CACHE attribute.
    * 
    * @param    n
    *           The cache value.
    */
   @Override
   public void setCache(long n)
   {
      UnimplementedFeature.missing("QUERY:CACHE");
   }

   /**
    * Conversion of IS-OPEN attribute (KW_IS_OPEN).
    *
    * Getter of IS-OPEN attribute.
    *
    * @return current value of IS-OPEN attribute.
    */
   public logical isOpen()
   {
      return logical.of(!closed);
   }

   /**
    * Get the value of the ADM-DATA attribute.
    * 
    * @return   See above.
    */
   @Override
   public character getADMData()
   {
      return new character(admData);
   }

   /**
    * Set the value of the ADM-DATA attribute.
    * 
    * @param    value
    *           The new value.
    */
   @Override
   public void setADMData(String value)
   {
      this.admData = value;
   }

   /**
    * Set the value of the ADM-DATA attribute.
    * 
    * @param    value
    *           The new value.
    */
   @Override
   public void setADMData(character value)
   {
      this.admData = value.toJavaType();
   }

   /**
    * Gets the the unique ID number associated to this object by the underlying system. Not the 
    * same as the handle value itself.
    * 
    * @return   The integer number of the children.
    */
   @Override
   public integer getUniqueID()
   {
      if (uniqueID == null)
      {
         this.uniqueID = UniqueIdGenerator.getUniqueId(IdKind.QUERY);
      }
      
      return new integer(uniqueID);
   }

   /**
    * Delete the resource.
    * 
    * @return   <code>true</code> if the resource was deleted.
    */
   @Override
   protected boolean resourceDelete()
   {
      if (!dynamic && !implicitDeletion())
      {
         // static queries can't be deleted.
         
         // although a static query handle obtained via HANDLE attribute can be deleted and a 
         // subsequent access of the HANDLE attribute on the static query returns a handle with a
         // different ID, P2J doesn't allow static queries to be deleted (at least until we need
         // to implement this too).
         return false;
      }
      
      // remove the 'last query' from the BufferImpl.lastQuery
      for (int i = 0; i < buffers.size(); i++)
      {
         Buffer buf = buffers.get(i);
         ((BufferImpl) buf).resetLastQuery(this);
      }
      
      // perform cleanup only when the query gets deleted
      cleanup();
      notifyQueryDeleted();
      
      resetQuery();
      
      // all queries can be deleted
      this.valid = false;
      
      ControlFlowOps.invalidateCallSiteCache(this);
      
      // release the delegate, if closed
      if (closed)
      {
         this.delegate = null;
      }
      
      return true;
   }

   /**
    * Conversion of GET-NEXT method (KW_GET_NEXT), which returns a Java boolean, for internal usage.
    *
    * Moves a query object's result list pointer ahead one row.
    *
    * @return  <code>true</code> if the next record in the query is found. If the query is not
    *          open or the next record cannot be found (query is empty or the query result list
    *          pointer is on the last row), the method returns <code>false</code>.
    */
   @Override
   public boolean _getNext()
   {
      if (!canGet())
      {
         return false;
      }
      
      advanced = true;
      
      boolean ret = getDelegate()._getNext();
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-NEXT method (KW_GET_NEXT).
    *
    * Moves a query object's result list pointer ahead one row.
    *
    * @param   lockType
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    *
    * @return  <code>true</code> if the next record in the query is found. If the query is not
    *          open or the next record cannot be found (query is empty or the query result list
    *          pointer is on the last row), the method returns <code>false</code>. If the query
    *          object handle is invalid, the method returns the Unknown value (?).
    */
   public logical getNext(LockType lockType)
   {
      if (!canGet())
      {
         return logical.of(false);
      }
      
      advanced = true;
      
      logical ret = getDelegate().getNext(lockType);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-NEXT method (KW_GET_NEXT).
    *
    * Moves a query object's result list pointer ahead one row.
    *
    * @param   lock
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    *
    * @return  <code>true</code> if the next record in the query is found. If the query is not
    *          open or the next record cannot be found (query is empty or the query result list
    *          pointer is on the last row), the method returns <code>false</code>. If the query
    *          object handle is invalid, the method returns the Unknown value (?).
    *
    * @throws  IllegalArgumentException
    *          if <code>lock</code> has not valid internal value.
    */
   public logical getNext(long lock)
   {
      if (!canGet())
      {
         return logical.of(false);
      }
      
      advanced = true;
      
      logical ret = getDelegate().getNext(lock);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-NEXT method (KW_GET_NEXT).
    *
    * Moves a query object's result list pointer ahead one row.
    *
    * @param   lock
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    *
    * @return  <code>true</code> if the next record in the query is found. If the query is not
    *          open or the next record cannot be found (query is empty or the query result list
    *          pointer is on the last row), the method returns <code>false</code>. If the query
    *          object handle is invalid, the method returns the Unknown value (?).
    *
    * @throws  IllegalArgumentException
    *          if <code>lock</code> has not valid internal value.
    */
   public logical getNext(NumberType lock)
   {
      if (!canGet())
      {
         return logical.of(false);
      }
      
      advanced = true;
      
      logical ret = getDelegate().getNext(lock);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-NEXT method (KW_GET_NEXT).
    *
    * Moves a query object's result list pointer ahead one row.
    *
    * @param   lock
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    * @param   nowait
    *          NO-WAIT
    *
    * @return  <code>true</code> if the next record in the query is found. If the query is not
    *          open or the next record cannot be found (query is empty or the query result list
    *          pointer is on the last row), the method returns <code>false</code>. If the query
    *          object handle is invalid, the method returns the Unknown value (?).
    *
    * @throws  IllegalArgumentException
    *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
    */
   public logical getNext(long lock, long nowait)
   {
      if (!canGet())
      {
         return logical.of(false);
      }
      
      advanced = true;
      
      logical ret = getDelegate().getNext(lock, nowait);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-NEXT method (KW_GET_NEXT).
    *
    * Moves a query object's result list pointer ahead one row.
    *
    * @param   lock
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    * @param   nowait
    *          NO-WAIT
    *
    * @return  <code>true</code> if the next record in the query is found. If the query is not
    *          open or the next record cannot be found (query is empty or the query result list
    *          pointer is on the last row), the method returns <code>false</code>. If the query
    *          object handle is invalid, the method returns the Unknown value (?).
    *
    * @throws  IllegalArgumentException
    *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
    */
   public logical getNext(long lock, NumberType nowait)
   {
      if (!canGet())
      {
         return logical.of(false);
      }
      
      advanced = true;
      
      logical ret = getDelegate().getNext(lock, nowait);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-NEXT method (KW_GET_NEXT).
    *
    * Moves a query object's result list pointer ahead one row.
    *
    * @param   lock
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    * @param   nowait
    *          NO-WAIT
    *
    * @return  <code>true</code> if the next record in the query is found. If the query is not
    *          open or the next record cannot be found (query is empty or the query result list
    *          pointer is on the last row), the method returns <code>false</code>. If the query
    *          object handle is invalid, the method returns the Unknown value (?).
    *
    * @throws  IllegalArgumentException
    *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
    */
   public logical getNext(NumberType lock, long nowait)
   {
      if (!canGet())
      {
         return logical.of(false);
      }
      
      advanced = true;
      
      logical ret = getDelegate().getNext(lock, nowait);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-NEXT method (KW_GET_NEXT).
    *
    * Moves a query object's result list pointer ahead one row.
    *
    * @param   lock
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    * @param   nowait
    *          NO-WAIT
    *
    * @return  <code>true</code> if the next record in the query is found. If the query is not
    *          open or the next record cannot be found (query is empty or the query result list
    *          pointer is on the last row), the method returns <code>false</code>. If the query
    *          object handle is invalid, the method returns the Unknown value (?).
    *
    * @throws  IllegalArgumentException
    *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
    */
   public logical getNext(NumberType lock, NumberType nowait)
   {
      if (!canGet())
      {
         return logical.of(false);
      }
      
      advanced = true;
      
      logical ret = getDelegate().getNext(lock, nowait);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-PREV method (KW_GET_PREV).
    *
    * Moves a query object's result list pointer back one row.
    *
    * @return  <code>true</code> if the previous record in the query is found. If the query is
    *          not open or the previous record cannot be found (query is empty or the query
    *          result list pointer is on the first row), the method returns <code>false</code>.
    *          If the query object handle is invalid, the method returns the Unknown value (?).
    */
   public logical getPrevious()
   {
      if (!canGet() || !canLastOrPrev())
      {
         return logical.of(false);
      }
      
      logical ret = getDelegate().getPrevious();
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-PREV method (KW_GET_PREV).
    *
    * Moves a query object's result list pointer back one row.
    *
    * @param   lock
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    *
    * @return  <code>true</code> if the previous record in the query is found. If the query is
    *          not open or the previous record cannot be found (query is empty or the query
    *          result list pointer is on the first row), the method returns <code>false</code>.
    *          If the query object handle is invalid, the method returns the Unknown value (?).
    *
    * @throws  IllegalArgumentException
    *          if <code>lock</code> has not valid internal value.
    */
   public logical getPrevious(long lock)
   {
      if (!canGet() || !canLastOrPrev())
      {
         return logical.of(false);
      }
      
         logical ret = getDelegate().getPrevious(lock);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-PREV method (KW_GET_PREV).
    *
    * Moves a query object's result list pointer back one row.
    *
    * @param   lockType
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    *
    * @return  <code>true</code> if the previous record in the query is found. If the query is
    *          not open or the previous record cannot be found (query is empty or the query
    *          result list pointer is on the first row), the method returns <code>false</code>.
    *          If the query object handle is invalid, the method returns the Unknown value (?).
    *
    * @throws  IllegalArgumentException
    *          if <code>lock</code> has not valid internal value.
    */
   public logical getPrevious(LockType lockType)
   {
      if (!canGet() || !canLastOrPrev())
      {
         return logical.of(false);
      }
      
      logical ret = getDelegate().getPrevious(lockType);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-PREV method (KW_GET_PREV).
    *
    * Moves a query object's result list pointer back one row.
    *
    * @param   lock
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    *
    * @return  <code>true</code> if thgetPe previous record in the query is found. If the query is
    *          not open or the previous record cannot be found (query is empty or the query
    *          result list pointer is on the first row), the method returns <code>false</code>.
    *          If the query object handle is invalid, the method returns the Unknown value (?).
    *
    * @throws  IllegalArgumentException
    *          if <code>lock</code> has not valid internal value.
    */
   public logical getPrevious(NumberType lock)
   {
      if (!canGet() || !canLastOrPrev())
      {
         return logical.of(false);
      }
      
      logical ret = getDelegate().getPrevious(lock);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-PREV method (KW_GET_PREV).
    *
    * Moves a query object's result list pointer back one row.
    *
    * @param   lock
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    * @param   nowait
    *          NO-WAIT
    *
    * @return  <code>true</code> if the previous record in the query is found. If the query is
    *          not open or the previous record cannot be found (query is empty or the query
    *          result list pointer is on the first row), the method returns <code>false</code>.
    *          If the query object handle is invalid, the method returns the Unknown value (?).
    *
    * @throws  IllegalArgumentException
    *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
    */
   public logical getPrevious(long lock, long nowait)
   {
      if (!canGet() || !canLastOrPrev())
      {
         return logical.of(false);
      }
      
      logical ret = getDelegate().getPrevious(lock, nowait);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-PREV method (KW_GET_PREV).
    *
    * Moves a query object's result list pointer back one row.
    *
    * @param   lock
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    * @param   nowait
    *          NO-WAIT
    *
    * @return  <code>true</code> if the previous record in the query is found. If the query is
    *          not open or the previous record cannot be found (query is empty or the query
    *          result list pointer is on the first row), the method returns <code>false</code>.
    *          If the query object handle is invalid, the method returns the Unknown value (?).
    *
    * @throws  IllegalArgumentException
    *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
    */
   public logical getPrevious(NumberType lock, long nowait)
   {
      if (!canGet() || !canLastOrPrev())
      {
         return logical.of(false);
      }
      
      logical ret = getDelegate().getPrevious(lock, nowait);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-PREV method (KW_GET_PREV).
    *
    * Moves a query object's result list pointer back one row.
    *
    * @param   lock
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    * @param   nowait
    *          NO-WAIT
    *
    * @return  <code>true</code> if the previous record in the query is found. If the query is
    *          not open or the previous record cannot be found (query is empty or the query
    *          result list pointer is on the first row), the method returns <code>false</code>.
    *          If the query object handle is invalid, the method returns the Unknown value (?).
    *
    * @throws  IllegalArgumentException
    *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
    */
   public logical getPrevious(long lock, NumberType nowait)
   {
      if (!canGet() || !canLastOrPrev())
      {
         return logical.of(false);
      }
      
      logical ret = getDelegate().getPrevious(lock, nowait);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-PREV method (KW_GET_PREV).
    *
    * Moves a query object's result list pointer back one row.
    *
    * @param   lock
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    * @param   nowait
    *          NO-WAIT
    *
    * @return  <code>true</code> if the previous record in the query is found. If the query is
    *          not open or the previous record cannot be found (query is empty or the query
    *          result list pointer is on the first row), the method returns <code>false</code>.
    *          If the query object handle is invalid, the method returns the Unknown value (?).
    *
    * @throws  IllegalArgumentException
    *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
    */
   public logical getPrevious(NumberType lock, NumberType nowait)
   {
      if (!canGet() || !canLastOrPrev())
      {
         return logical.of(false);
      }
      
      logical ret = getDelegate().getPrevious(lock, nowait);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-FIRST method (KW_GET_1ST).
    *
    * Moves a query object's result list pointer to the first row.
    *
    * @return  <code>true</code> if the first record in the query is found. If the query is not
    *          open or the first record cannot be found (query is empty), the method returns
    *          <code>false</code>. If the query object handle is invalid, the method returns
    *          the Unknown value (?).
    */
   public logical getFirst()
   {
      if (!canGet() || !canGetFirst())
      {
         return logical.of(false);
      }
      
      advanced = true;
      
      logical ret = getDelegate().getFirst();
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-FIRST method (KW_GET_1ST).
    *
    * Moves a query object's result list pointer to the first row.
    *
    * @param   lock
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    *
    * @return  <code>true</code> if the first record in the query is found. If the query is not
    *          open or the first record cannot be found (query is empty), the method returns
    *          <code>false</code>. If the query object handle is invalid, the method returns
    *          the Unknown value (?).
    *
    * @throws  IllegalArgumentException
    *          if <code>lock</code> has not valid internal value.
    */
   public logical getFirst(long lock)
   {
      if (!canGet() || !canGetFirst())
      {
         return logical.of(false);
      }
      
      advanced = true;
      
      logical ret = getDelegate().getFirst(lock);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-FIRST method (KW_GET_1ST).
    *
    * Moves a query object's result list pointer to the first row.
    *
    * @param   lock
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    *
    * @return  <code>true</code> if the first record in the query is found. If the query is not
    *          open or the first record cannot be found (query is empty), the method returns
    *          <code>false</code>. If the query object handle is invalid, the method returns
    *          the Unknown value (?).
    *
    * @throws  IllegalArgumentException
    *          if <code>lock</code> has not valid internal value.
    */
   public logical getFirst(NumberType lock)
   {
      if (!canGet() || !canGetFirst())
      {
         return logical.of(false);
      }
      
      advanced = true;
      
      logical ret = getDelegate().getFirst(lock);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-FIRST method (KW_GET_1ST).
    *
    * Moves a query object's result list pointer to the first row.
    *
    * @param   lockType
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    *
    * @return  <code>true</code> if the first record in the query is found. If the query is not
    *          open or the first record cannot be found (query is empty), the method returns
    *          <code>false</code>. If the query object handle is invalid, the method returns
    *          the Unknown value (?).
    *
    * @throws  IllegalArgumentException
    *          if <code>lock</code> has not valid internal value.
    */
   public logical getFirst(LockType lockType)
   {
      if (!canGet() || !canGetFirst())
      {
         return logical.of(false);
      }
      
      advanced = true;
      
      logical ret = getDelegate().getFirst(lockType);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-FIRST method (KW_GET_1ST).
    *
    * Moves a query object's result list pointer to the first row.
    *
    * @param   lock
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    * @param   nowait
    *          NO-WAIT
    *
    * @return  <code>true</code> if the first record in the query is found. If the query is not
    *          open or the first record cannot be found (query is empty), the method returns
    *          <code>false</code>. If the query object handle is invalid, the method returns
    *          the Unknown value (?).
    *
    * @throws  IllegalArgumentException
    *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
    */
   public logical getFirst(long lock, long nowait)
   {
      if (!canGet() || !canGetFirst())
      {
         return logical.of(false);
      }
      
      advanced = true;
      
      logical ret = getDelegate().getFirst(lock, nowait);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-FIRST method (KW_GET_1ST).
    *
    * Moves a query object's result list pointer to the first row.
    *
    * @param   lock
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    * @param   nowait
    *          NO-WAIT
    *
    * @return  <code>true</code> if the first record in the query is found. If the query is not
    *          open or the first record cannot be found (query is empty), the method returns
    *          <code>false</code>. If the query object handle is invalid, the method returns
    *          the Unknown value (?).
    *
    * @throws  IllegalArgumentException
    *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
    */
   public logical getFirst(NumberType lock, long nowait)
   {
      if (!canGet() || !canGetFirst())
      {
         return logical.of(false);
      }
      
      advanced = true;
      
      logical ret = getDelegate().getFirst(lock, nowait);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-FIRST method (KW_GET_1ST).
    *
    * Moves a query object's result list pointer to the first row.
    *
    * @param   lock
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    * @param   nowait
    *          NO-WAIT
    *
    * @return  <code>true</code> if the first record in the query is found. If the query is not
    *          open or the first record cannot be found (query is empty), the method returns
    *          <code>false</code>. If the query object handle is invalid, the method returns
    *          the Unknown value (?).
    *
    * @throws  IllegalArgumentException
    *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
    */
   public logical getFirst(long lock, NumberType nowait)
   {
      if (!canGet() || !canGetFirst())
      {
         return logical.of(false);
      }
      
      advanced = true;
      
      logical ret = getDelegate().getFirst(lock, nowait);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-FIRST method (KW_GET_1ST).
    *
    * Moves a query object's result list pointer to the first row.
    *
    * @param   lock
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    * @param   nowait
    *          NO-WAIT
    *
    * @return  <code>true</code> if the first record in the query is found. If the query is not
    *          open or the first record cannot be found (query is empty), the method returns
    *          <code>false</code>. If the query object handle is invalid, the method returns
    *          the Unknown value (?).
    *
    * @throws  IllegalArgumentException
    *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
    */
   public logical getFirst(NumberType lock, NumberType nowait)
   {
      if (!canGet() || !canGetFirst())
      {
         return logical.of(false);
      }
      
      advanced = true;
      
      logical ret = getDelegate().getFirst(lock, nowait);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-LAST method (KW_GET_LAST).
    *
    * Moves a query object's result list pointer to the last row.
    *
    * @return  <code>true</code> if the last record in the query is found. If the query is not
    *          open or the last record cannot be found (query is empty), the method returns
    *          <code>false</code>. If the query object handle is invalid, the method returns
    *          the Unknown value (?).
    */
   public logical getLast()
   {
      if (!canGet() || !canLastOrPrev())
      {
         return logical.of(false);
      }
      
      logical ret = getDelegate().getLast();
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-LAST method (KW_GET_LAST).
    *
    * Moves a query object's result list pointer to the last row.
    *
    * @param   lock
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    *
    * @return  <code>true</code> if the last record in the query is found. If the query is not
    *          open or the last record cannot be found (query is empty), the method returns
    *          <code>false</code>. If the query object handle is invalid, the method returns
    *          the Unknown value (?).
    *
    * @throws  IllegalArgumentException
    *          if <code>lock</code> has not valid internal value.
    */
   public logical getLast(long lock)
   {
      if (!canGet() || !canLastOrPrev())
      {
         return logical.of(false);
      }
      
      logical ret = getDelegate().getLast(lock);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-LAST method (KW_GET_LAST).
    *
    * Moves a query object's result list pointer to the last row.
    *
    * @param   lock
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    *
    * @return  <code>true</code> if the last record in the query is found. If the query is not
    *          open or the last record cannot be found (query is empty), the method returns
    *          <code>false</code>. If the query object handle is invalid, the method returns
    *          the Unknown value (?).
    *
    * @throws  IllegalArgumentException
    *          if <code>lock</code> has not valid internal value.
    */
   public logical getLast(NumberType lock)
   {
      if (!canGet() || !canLastOrPrev())
      {
         return logical.of(false);
      }
      
      logical ret = getDelegate().getLast(lock);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-LAST method (KW_GET_LAST).
    *
    * Moves a query object's result list pointer to the last row.
    *
    * @param   lockType
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    *
    * @return  <code>true</code> if the last record in the query is found. If the query is not
    *          open or the last record cannot be found (query is empty), the method returns
    *          <code>false</code>. If the query object handle is invalid, the method returns
    *          the Unknown value (?).
    *
    * @throws  IllegalArgumentException
    *          if <code>lock</code> has not valid internal value.
    */
   public logical getLast(LockType lockType)
   {
      if (!canGet() || !canLastOrPrev())
      {
         return logical.of(false);
      }
      
      logical ret = getDelegate().getLast(lockType);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-LAST method (KW_GET_LAST).
    *
    * Moves a query object's result list pointer to the last row.
    *
    * @param   lock
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    * @param   nowait
    *          NO-WAIT
    *
    * @return  <code>true</code> if the last record in the query is found. If the query is not
    *          open or the last record cannot be found (query is empty), the method returns
    *          <code>false</code>. If the query object handle is invalid, the method returns
    *          the Unknown value (?).
    *
    * @throws  IllegalArgumentException
    *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
    */
   public logical getLast(long lock, long nowait)
   {
      if (!canGet() || !canLastOrPrev())
      {
         return logical.of(false);
      }
      
      logical ret = getDelegate().getLast(lock, nowait);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-LAST method (KW_GET_LAST).
    *
    * Moves a query object's result list pointer to the last row.
    *
    * @param   lock
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    * @param   nowait
    *          NO-WAIT
    *
    * @return  <code>true</code> if the last record in the query is found. If the query is not
    *          open or the last record cannot be found (query is empty), the method returns
    *          <code>false</code>. If the query object handle is invalid, the method returns
    *          the Unknown value (?).
    *
    * @throws  IllegalArgumentException
    *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
    */
   public logical getLast(NumberType lock, long nowait)
   {
      if (!canGet() || !canLastOrPrev())
      {
         return logical.of(false);
      }
      
      logical ret = getDelegate().getLast(lock, nowait);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-LAST method (KW_GET_LAST).
    *
    * Moves a query object's result list pointer to the last row.
    *
    * @param   lock
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    * @param   nowait
    *          NO-WAIT
    *
    * @return  <code>true</code> if the last record in the query is found. If the query is not
    *          open or the last record cannot be found (query is empty), the method returns
    *          <code>false</code>. If the query object handle is invalid, the method returns
    *          the Unknown value (?).
    *
    * @throws  IllegalArgumentException
    *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
    */
   public logical getLast(long lock, NumberType nowait)
   {
      if (!canGet() || !canLastOrPrev())
      {
         return logical.of(false);
      }
      
      logical ret = getDelegate().getLast(lock, nowait);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-LAST method (KW_GET_LAST).
    *
    * Moves a query object's result list pointer to the last row.
    *
    * @param   lock
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    * @param   nowait
    *          NO-WAIT
    *
    * @return  <code>true</code> if the last record in the query is found. If the query is not
    *          open or the last record cannot be found (query is empty), the method returns
    *          <code>false</code>. If the query object handle is invalid, the method returns
    *          the Unknown value (?).
    *
    * @throws  IllegalArgumentException
    *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
    */
   public logical getLast(NumberType lock, NumberType nowait)
   {
      if (!canGet() || !canLastOrPrev())
      {
         return logical.of(false);
      }
      
      logical ret = getDelegate().getLast(lock, nowait);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-CURRENT() method (KW_GET_CUR).
    *
    * Refetches the current record or records associated with the query.
    *
    * @return  <code>true</code> if GET-CURRENT() succeeds, else <code>false</code>.
    */
   public logical getCurrent()
   {
      if (!canGet())
      {
         return logical.of(false);
      }
      
      logical ret = getDelegate().getCurrent();
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-CURRENT() method (KW_GET_CUR).
    *
    * Refetches the current record or records associated with the query.
    *
    * @param   lock
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    *
    * @return  <code>true</code> if GET-CURRENT() succeeds, else <code>false</code>.
    */
   public logical getCurrent(long lock)
   {
      if (!canGet())
      {
         return logical.of(false);
      }
      
      logical ret = getDelegate().getCurrent(lock);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-CURRENT() method (KW_GET_CUR).
    *
    * Refetches the current record or records associated with the query.
    *
    * @param   lock
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    *
    * @return  <code>true</code> if GET-CURRENT() succeeds, else <code>false</code>.
    */
   public logical getCurrent(NumberType lock)
   {
      if (!canGet())
      {
         return logical.of(false);
      }
      
      logical ret = getDelegate().getCurrent(lock);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-CURRENT() method (KW_GET_CUR).
    *
    * Refetches the current record or records associated with the query.
    *
    * @param   lockType of LockType
    *
    * @return  <code>true</code> if GET-CURRENT() succeeds, else <code>false</code>.
    */
   public logical getCurrent(LockType lockType)
   {
      if (!canGet())
      {
         return logical.of(false);
      }
      
      logical ret = getDelegate().getCurrent(lockType);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-CURRENT() method (KW_GET_CUR).
    *
    * Refetches the current record or records associated with the query.
    *
    * @param   lock
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    * @param   nowait
    *          NO-WAIT
    *
    * @return  <code>true</code> if GET-CURRENT() succeeds, else <code>false</code>.
    */
   public logical getCurrent(long lock, long nowait)
   {
      if (!canGet())
      {
         return logical.of(false);
      }
      
      logical ret = getDelegate().getCurrent(lock, nowait);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-CURRENT() method (KW_GET_CUR).
    *
    * Refetches the current record or records associated with the query.
    *
    * @param   lock
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    * @param   nowait
    *          NO-WAIT
    *
    * @return  <code>true</code> if GET-CURRENT() succeeds, else <code>false</code>.
    */
   public logical getCurrent(NumberType lock, long nowait)
   {
      if (!canGet())
      {
         return logical.of(false);
      }
      
      logical ret = getDelegate().getCurrent(lock, nowait);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-CURRENT() method (KW_GET_CUR).
    *
    * Refetches the current record or records associated with the query.
    *
    * @param   lock
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    * @param   nowait
    *          NO-WAIT
    *
    * @return  <code>true</code> if GET-CURRENT() succeeds, else <code>false</code>.
    */
   public logical getCurrent(long lock, NumberType nowait)
   {
      if (!canGet())
      {
         return logical.of(false);
      }
      
      logical ret = getDelegate().getCurrent(lock, nowait);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Conversion of GET-CURRENT() method (KW_GET_CUR).
    *
    * Refetches the current record or records associated with the query.
    *
    * @param   lock
    *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
    * @param   nowait
    *          NO-WAIT
    *
    * @return  <code>true</code> if GET-CURRENT() succeeds, else <code>false</code>.
    */
   public logical getCurrent(NumberType lock, NumberType nowait)
   {
      if (!canGet())
      {
         return logical.of(false);
      }
      
      logical ret = getDelegate().getCurrent(lock, nowait);
      maybeFireCallback();
      return ret;
   }
   
   /**
    * Creates an entry in the result list for the current row. Implements the 4GL
    * CREATE-RESULT-LIST-ENTRY() method. Created entry contains id(s) of the record(s) currently
    * located in the backing buffer(s).
    *
    * @return <code>true</code> on success.
    */
   @Override
   public logical createResultListEntry()
   {
      if (externalResultListHandler != null)
      {
         return externalResultListHandler.createResultListEntry();
      }

      if (!isOpen().booleanValue())
      {
         return logical.of(false);
      }
      else if (!isScrolling())
      {
         UnimplementedFeature.partial(
               "CREATE-RESULT-LIST-ENTRY is not implemented for non-scrolling queries");
         return logical.of(false);
      }

      return createResultListEntryWorker();
   }

   /**
    * Calls delegate's {@link P2JQuery#createResultListEntry()}.
    *
    * @return result of execution of delegate's {@link P2JQuery#createResultListEntry()}.
    */
   public logical createResultListEntryWorker()
   {
      return getDelegate().createResultListEntry();
   }

   /**
    * Calls delegate's {@link P2JQuery#deleteResultListEntry()}.
    *
    * @return result of execution of delegate's {@link P2JQuery#deleteResultListEntry()}.
    */
   public logical deleteResultListEntryWorker()
   {
      return getDelegate().deleteResultListEntry();
   }

   /**
    * Deletes the current row of a query's result list. Implements the 4GL
    * DELETE-RESULT-LIST-ENTRY() method.
    *
    * @return <code>true</code> on success.
    */
   @Override
   public logical deleteResultListEntry()
   {
      if (externalResultListHandler != null)
      {
         return externalResultListHandler.deleteResultListEntry();
      }

      if (!canGet())
      {
         return logical.of(false);
      }

      return deleteResultListEntryWorker();
   }

   /**
    * Deletes the current row of a query's result list. Implements the 4GL
    * DELETE-RESULT-LIST-ENTRY() method.
    *
    * @param  allowBetweenRows
    *         If <code>true</code> then the cursor can be positioned between rows (the next
    *         row will be deleted). <code>false</code> for conventional DELETE-RESULT-LIST-ENTRY()
    *         mode where the cursor should be positioned on a row (otherwise <code>false</code> is
    *         returned).
    *
    * @return <code>true</code> on success.
    */
   @Override
   public logical deleteResultListEntry(boolean allowBetweenRows)
   {
      if (!canGet())
      {
         return logical.of(false);
      }

      return getDelegate().deleteResultListEntry(allowBetweenRows);
   }

   /**
    * Set the filter that handles parameters passed to the query. E.g. it can take input field
    * references and substitute them with snapshot values, if necessary.
    *
    * @param parameterFilter
    *        The filter that handles passed parameters.
    */
   @Override
   public void setParameterFilter(ParameterFilter parameterFilter)
   {
      getDelegate().setParameterFilter(parameterFilter);
   }
   
   /**
    * Conversion of NUM-BUFFERS() method (KW_NUM_BUFF).
    *
    * @return  the number of buffers in a query or DataSet object.
    */
   public integer numBuffers()
   {
      return dynamic || dynamicDelegate || delegate == DEFAULT_DELEGATE ? new integer(buffers.size()) 
                                                                        : getDelegate().numBuffers();
   }
   
   /**
    * Setter for SKIP-DELETED-RECORD query attribute.
    *
    * @param   on
    *          New value for the attribute.
    */
   @Override
   public void setSkipDeletedRecord(logical on)
   {
      if (on == null || on.isUnknown())
      {
         ErrorManager.recordOrShowError(4083, "SKIP-DELETED-RECORD", "QUERY widget");
         return; // attribute remains unchanged
      }
      
      skipDeletedRecordDisposition = on.booleanValue();
      if (delegate != null)
      {
         delegate.setSkipDeletedRecord(on);
      }
   }
   
   /**
    * Informs the query that the next operations will be performed for filling browse rows, so it should not
    * return deleted rows/records (if argument is {@code true}). That is, temporarily overwrite the
    * SKIP-DELETED-RECORDS until the flag is turned off.
    *
    * @param   on
    *          if {@code true} the deleted rows will not be returned because the query is managed by the
    *          browse widget.
    */
   @Override
   public void setFillingBrowseRows(boolean on)
   {
      if (delegate != null)
      {
         delegate.setFillingBrowseRows(on);
      }
   }
   
   /**
    * Checks whether the query that the next operations will be performed for filling browse rows, so it
    * should not return deleted rows/records (if argument is {@code true}). That is, temporarily overwrite the
    * SKIP-DELETED-RECORDS until the flag is turned off.
    *
    * @return  {@code true} if the deleted rows will not be returned because the query is managed by the
    *          browse widget. 
    */
   public boolean isFillingBrowseRows()
   {
      return delegate != null && delegate.isFillingBrowseRows();
   }
   
   /**
    * Get value of SKIP-DELETED-RECORD attribute of the query.
    *
    * @return  the value of SKIP-DELETED-RECORD attribute of the query.
    */
   @Override
   public logical isSkipDeletedRecord()
   {
      if (delegate == null || delegate == DEFAULT_DELEGATE)
      {
         return logical.of(skipDeletedRecordDisposition);
      }
      
      return delegate.isSkipDeletedRecord();
   }
   
   /**
    * Associates an internal procedure with an ABL callback event.
    * <p>
    * This method returns false if the event name is not valid.
    * 
    * @param    event
    *           The event name, must evaluate to one of the events supported by implementing object. 
    * @param    proc
    *           The internal procedure to be executed for this event, which will be executed using
    *           the current THIS-PROCEDURE reference. To remove a callback mapping, set the this
    *           parameter to the empty string.
    *           
    * @return   {@code true} if the event was registered.
    */
   @Override
   public logical setCallbackProcedure(String event, String proc)
   {
      return setCallbackProcedure(event, proc, null);
   }

   /**
    * Associates an internal procedure with an ABL callback event.
    * <p>
    * This method returns false if the event name is not valid.
    *
    * @param   event
    *          The event name.
    * @param   proc
    *          The internal procedure to be executed for this event, which will be executed using
    *          the current THIS-PROCEDURE reference. To remove a callback mapping, set the this
    *          parameter to the empty string.
    *
    * @return   {@code true} if the event was registered.
    */
   @Override
   public logical setCallbackProcedure(String event, character proc)
   {
      return setCallbackProcedure(event, proc.toJavaType(), null);
   }

   /**
    * Associates an internal procedure with an ABL callback event.
    * <p>
    * This method returns false if the event name is not valid.
    *
    * @param   event
    *          The event name.
    * @param   proc
    *          The internal procedure to be executed for this event, which will be executed using
    *          the current THIS-PROCEDURE reference. To remove a callback mapping, set the this
    *          parameter to the empty string.
    *
    * @return   {@code true} if the event was registered.
    */
   @Override
   public logical setCallbackProcedure(character event, character proc)
   {
      return setCallbackProcedure(event.toJavaType(), proc.toJavaType(), null);
   }
   
   /**
    * Associates an internal procedure with an ABL callback event.
    * <p>
    * This method returns false if the event name is not valid or if the procedure's context is
    * not a valid handle.
    * 
    * @param    event
    *           The event name, must evaluate to one of the events supported by implementing object. 
    * @param    proc
    *           The internal procedure to be executed for this event. To remove a callback 
    *           mapping, set the this parameter to the empty string.
    * @param    context
    *           The procedure handle where the internal procedure will be searched and executed.
    *           
    * @return   {@code true} if the event was registered.
    */
   @Override
   public logical setCallbackProcedure(character event, String proc, handle context)
   {
      return setCallbackProcedure(event.toJavaType(), proc, context);
   }

   /**
    * Associates an internal procedure with an ABL callback event.
    * <p>
    * This method returns false if the event name is not valid or if the procedure's context is
    * not a valid handle.
    *
    * @param   event
    *          The event name.
    * @param   proc
    *          The internal procedure to be executed for this event, which will be executed using
    *          the current THIS-PROCEDURE reference. To remove a callback mapping, set the this
    *          parameter to the empty string.
    * @param   context
    *          The procedure handle where the internal procedure will be searched and executed.
    *
    * @return   {@code true} if the event was registered.
    */
   @Override
   public logical setCallbackProcedure(String event, character proc, handle context)
   {
      return setCallbackProcedure(event, proc.toJavaType(), context);
   }
   
   /**
    * Associates an internal procedure with an ABL callback event.
    * <p>
    * This method returns false if the event name is not valid or if the procedure's context is not a valid
    * handle.
    *
    * @param   event
    *          The event name.
    * @param   proc
    *          The internal procedure to be executed for this event, which will be executed using the current
    *          THIS-PROCEDURE reference. To remove a callback mapping, set the this parameter to the empty
    *          string.
    * @param   context
    *          The procedure handle where the internal procedure will be searched and executed.
    *
    * @return   {@code true} if the event was registered.
    */
   @Override
   public logical setCallbackProcedure(character event, character proc, handle context)
   {
      return setCallbackProcedure(event.toJavaType(), proc.toJavaType(), context);
   }
   
   /**
    * Applies a callback procedure, which allows execution of a defined event without duplicating
    * the event procedure definition.
    *
    * @param   eventName
    *          The event whose callback will be called.
    *
    * @return  {@code true} if operation is successful.
    */
   @Override
   public logical applyCallback(Text eventName)
   {
      return applyCallback(eventName.toJavaType());
   }

   /**
    * Retrieves the name of the internal procedure associated with the ABL callback for the
    * specified event.
    *
    * @param   eventName
    *          The name of the event.
    *
    * @return  the name of the internal procedure associated with specified event.
    */
   @Override
   public character getCallbackProcName(Text eventName)
   {
      return getCallbackProcName(eventName.toJavaType());
   }
   
   /**
    * Retrieves the handle of the procedure that contains the internal procedure associated
    * with the ABL callback for the specified event
    *
    * @param   eventName
    *          The name of the event.
    *
    * @return  a handle to the procedure that contains the callback procedure.
    */
   @Override
   public handle getCallbackProcContext(Text eventName)
   {
      return getCallbackProcContext(eventName.toJavaType());
   }
   
   /**
    * Configures a callback. Creates an association between a method within a class instance or
    * an internal procedure within a persistent procedure, with an ABL callback event.
    *
    * @param   callbackName
    *          The name of a callback.
    * @param   routineName
    *          The name of a method or an internal procedure to be associated.
    * @param   context
    *          The context in which the callback will be executed.
    *
    * @return  {@code true} if operation is successful and {@code false} if the parameters are
    *          invalid.
    */
   @Override
   public logical setCallback(Text callbackName, Text routineName, object<?> context)
   {
      return setCallback(callbackName.toJavaType(), routineName.toJavaType(), context);
   }
   
   /**
    * Configures a callback. Creates an association between a method within a class instance or
    * an internal procedure within a persistent procedure, with an ABL callback event.
    *
    * @param   callbackName
    *          The name of a callback.
    * @param   routineName
    *          The name of a method or an internal procedure to be associated.
    * @param   context
    *          The context in which the callback will be executed.
    *
    * @return  {@code true} if operation is successful and {@code false} if the parameters are
    *          invalid.
    */
   @Override
   public logical setCallback(String callbackName, String routineName, handle context)
   {
      return setCallbackProcedure(callbackName, routineName, context);
   }
   
   /**
    * Configures a callback. Creates an association between a method within a class instance or
    * an internal procedure within a persistent procedure, with an ABL callback event.
    *
    * @param   callbackName
    *          The name of a callback.
    * @param   routineName
    *          The name of a method or an internal procedure to be associated.
    * @param   context
    *          The context in which the callback will be executed.
    *
    * @return  {@code true} if operation is successful and {@code false} if the parameters are
    *          invalid.
    */
   @Override
   public logical setCallback(Text callbackName, Text routineName, handle context)
   {
      return setCallbackProcedure(callbackName.toJavaType(), routineName.toJavaType(), context);
   }
   
   /**
    * Configures a callback. Creates an association between a method within a class instance or
    * an internal procedure within a persistent procedure, with an ABL callback event.
    *
    * @param   callbackName
    *          The name of a callback.
    * @param   routineName
    *          The name of a method or an internal procedure to be associated.
    * @param   context
    *          The context in which the callback will be executed.
    *
    * @return  {@code true} if operation is successful and {@code false} if the parameters are
    *          invalid.
    */
   @Override
   public logical setCallback(String callbackName, Text routineName, handle context)
   {
      return setCallbackProcedure(callbackName, routineName.toJavaType(), context);
   }

   /**
    * Configures a callback. Creates an association between a method within a class instance or
    * an internal procedure within a persistent procedure, with an ABL callback event.
    *
    * @param   callbackName
    *          The name of a callback.
    * @param   routineName
    *          The name of a method or an internal procedure to be associated.
    *
    * @return  {@code true} if operation is successful and {@code false} if the parameters are
    *          invalid.
    */
   @Override
   public logical setCallback(String callbackName, String routineName)
   {
      return setCallback(callbackName, routineName, (object<?>) null);
   }
   
   /**
    * Configures a callback. Creates an association between a method within a class instance or
    * an internal procedure within a persistent procedure, with an ABL callback event.
    *
    * @param   callbackName
    *          The name of a callback.
    * @param   routineName
    *          The name of a method or an internal procedure to be associated.
    *
    * @return  {@code true} if operation is successful and {@code false} if the parameters are
    *          invalid.
    */
   @Override
   public logical setCallback(Text callbackName, Text routineName)
   {
      return setCallback(callbackName.toJavaType(), routineName.toJavaType(), (object<?>) null);
   }
   
   /**
    * Configures a callback. Creates an association between a method within a class instance or
    * an internal procedure within a persistent procedure, with an ABL callback event.
    *
    * @param   callbackName
    *          The name of a callback.
    * @param   routineName
    *          The name of a method or an internal procedure to be associated.
    *
    * @return  {@code true} if operation is successful and {@code false} if the parameters are
    *          invalid.
    */
   @Override
   public logical setCallback(Text callbackName, String routineName)
   {
      return setCallback(callbackName.toJavaType(), routineName);
   }
   
   /**
    * Configures a callback. Creates an association between a method within a class instance or
    * an internal procedure within a persistent procedure, with an ABL callback event.
    *
    * @param   callbackName
    *          The name of a callback.
    * @param   routineName
    *          The name of a method or an internal procedure to be associated.
    *
    * @return  {@code true} if operation is successful and {@code false} if the parameters are
    *          invalid.
    */
   @Override
   public logical setCallback(String callbackName, Text routineName)
   {
      return setCallback(callbackName, routineName.toJavaType());
   }

   /**
    * Configures a callback. Creates an association between a method within a class instance or
    * an internal procedure within a persistent procedure, with an ABL callback event.
    *
    * @param   callbackName
    *          The name of a callback.
    * @param   routineName
    *          The name of a method or an internal procedure to be associated.
    * @param   context
    *          The context in which the callback will be executed.
    *
    * @return  {@code true} if operation is successful and {@code false} if the parameters are
    *          invalid.
    */
   @Override
   public logical setCallback(String callbackName, Text routineName, object<?> context)
   {
      return setCallback(callbackName, routineName.toJavaType(), context);
   }
   
   /**
    * Configures a callback. Creates an association between a method within a class instance or
    * an internal procedure within a persistent procedure, with an ABL callback event.
    *
    * @param   callbackName
    *          The name of a callback.
    * @param   routineName
    *          The name of a method or an internal procedure to be associated.
    * @param   context
    *          The context in which the callback will be executed.
    *
    * @return  {@code true} if operation is successful and {@code false} if the parameters are
    *          invalid.
    */
   @Override
   public logical setCallback(Text callbackName, String routineName, object<?> context)
   {
      return setCallback(callbackName.toJavaType(), routineName, context);
   }
   
   /**
    * Configures a callback. Creates an association between a method within a class instance or
    * an internal procedure within a persistent procedure, with an ABL callback event.
    *
    * @param   callbackName
    *          The name of a callback.
    * @param   routineName
    *          The name of a method or an internal procedure to be associated.
    * @param   context
    *          The context in which the callback will be executed.
    *
    * @return  {@code true} if operation is successful and {@code false} if the parameters are
    *          invalid.
    */
   @Override
   public logical setCallback(Text callbackName, String routineName, handle context)
   {
      return setCallback(callbackName.toJavaType(), routineName, context);
   }

   /**
    * Associates an internal procedure with an ABL callback event.
    * <p>
    * This method returns false if the event name is not valid.
    *
    * @param   event
    *          The event name.
    * @param   proc
    *          The internal procedure to be executed for this event, which will be executed using
    *          the current THIS-PROCEDURE reference. To remove a callback mapping, set the this
    *          parameter to the empty string.
    *
    * @return   {@code true} if the event was registered.
    */
   @Override
   public logical setCallbackProcedure(character event, String proc)
   {
      return setCallbackProcedure(event.toJavaType(), proc, null);
   }

   
   /**
    * Associates an internal procedure with an ABL callback event.
    *
    * @param   eventName
    *          The eventName of the event.
    * @param   callback
    *          The eventName of the internal procedure associated with the callback event.
    * @param   context
    *          A handle to a procedure that contains the internal procedure specified by {@code callback}. If
    *          not specified, {@code THIS-PROCEDURE} is used as the procedure context.
    *
    * @return  {@code true} when the method ends with success.
    */
   @Override
   public logical setCallbackProcedure(String eventName, String callback, handle context)
   {
      if (!isCallbackName(eventName))
      {
         return logical.of(false);
      }
      
      if (getDataSet() == null)
      {
         ErrorManager.recordOrShowError(11951);
         // SET-CALLBACK-PROCEDURE is only valid for buffers that are members of a dataset.
         return logical.of(false);
      }
      
      if (callback != null)
      {
         if (context == null || context.isUnknown())
         {
            // defaulting to THIS-PROCEDURE
            context = pm.thisProcedure();
         }
         else
         {
            if (!context._isValid() || !(context.getResource() instanceof PersistentProcedure))
            {
               ErrorManager.recordOrShowError(13273);
               // Third argument to SET-CALLBACK must be a valid procedure handle or object reference.
               return logical.of(false);
            }
         }
         
         this.callback = new CallbackData(callback, context, null, OFF_END_CALL_SITE);
      }
      
      return logical.of(true);
   }
   
   /**
    * Configures a callback. Creates an association between a method within a class instance or an internal
    * procedure within a persistent procedure, with an ABL callback event.
    *
    * @param   callbackName
    *          The name of a callback.
    * @param   routineName
    *          The name of a method or an internal procedure to be associated.
    * @param   context
    *          The context in which the callback will be executed.
    *
    * @return  {@code true} if {@code callbackName} is a correct callback name. The rest of parameters are
    *          ignored (note: manual states otherwise).
    */
   @Override
   public logical setCallback(String callbackName, String routineName, object<?> context)
   {
      if (!isCallbackName(callbackName))
      {
         return logical.of(false);
      }
      
      if (getDataSet() == null)
      {
         ErrorManager.recordOrShowError(11951);
         // SET-CALLBACK-PROCEDURE is only valid for buffers that are members of a dataset.
         return logical.of(false);
      }
      
      if (routineName != null)
      {
         CallbackData cbd;
         if (context == null || context.isUnknown())
         {
            // defaulting to THIS-OBJECT or to THIS-PROCEDURE, depending on the context
            if (ObjectOps.thisObject().isUnknown())
            {
               cbd = new CallbackData(routineName, pm.thisProcedure(), null, OFF_END_CALL_SITE);
            }
            else
            {
               cbd = new CallbackData(routineName, null, ObjectOps.thisObject(), null);
            }
         }
         else
         {
            cbd = new CallbackData(routineName, null, context, null);
         }
         
         this.callback = cbd;
      }
      
      return logical.of(true);
   }
   
   /**
    * Applies a callback procedure, which allows execution of a defined event without duplicating the event
    * procedure definition.
    *
    * @param   eventName
    *          The event whose callback will be called.
    *
    * @return  {@code true} if operation is successful.
    */
   public logical applyCallback(String eventName)
   {
      DataSet ds = getDataSet();
      if (ds == null)
      {
         ErrorManager.recordOrShowError(11949);
         // APPLY-CALLBACK is only for buffers that are members of datasets.
         return logical.of(false);
      }
      
      if (!isCallbackName(eventName))
      {
         return logical.of(false);
      }
   
      return logical.of(invokeCallback(asHandle(), this.callback));
   }
   
   /**
    * Retrieves the name of the internal procedure associated with the ABL callback for the specified event.
    *
    * @param   eventName
    *          The name of the event.
    *
    * @return  the name of the internal procedure associated with specified event.
    */
   @Override
   public character getCallbackProcName(String eventName)
   {
      if (getDataSet() == null)
      {
         if (buffers != null && buffers.size() > 0)
         {
            ErrorManager.recordOrShowError(12788, getName(), ((BufferImpl) buffers.get(0)).doGetName());
            // OFF-END CALLBACK not supported for query <name> whose buffer <name> is not in a dataset.
            return new character();
         }
      }
      
      if (!isCallbackName(eventName))
      {
         return new character();
      }
      
      if (this.callback == null)
      {
         return new character();
      }
   
      return new character(this.callback.getTarget());
   }
   
   /**
    * Retrieves the handle of the procedure that contains the internal procedure associated with the ABL
    * callback for the specified event
    *
    * @param   eventName
    *          The name of the event.
    *
    * @return  a handle to the procedure that contains the callback procedure.
    */
   @Override
   public handle getCallbackProcContext(String eventName)
   {
      if (getDataSet() == null)
      {
         if (buffers != null && buffers.size() > 0)
         {
            ErrorManager.recordOrShowError(12788, getName(), ((BufferImpl) buffers.get(0)).doGetName());
            // OFF-END CALLBACK not supported for query <name> whose buffer <name> is not in a dataset.
            return new handle();
         }
      }
      
      if (!isCallbackName(eventName))
      {
         return new handle();
      }
      
      if (this.callback == null || this.callback.getProcedure() == null)
      {
         return new handle();
      }
   
      return new handle(this.callback.getProcedure());
   }
   
   /**
    * Specifies the fields included in a record retrieval.
    *
    * @param   dmo
    *          DMO proxy which defines the buffer for which the fields are specified.
    * @param   fields
    *          The fields included in a record retrieval. If no fields are specified, only record
    *          identifiers are retrieved. No subscripts can be specified for extent fields.
    */
   public void include(DataModelObject dmo, String ... fields)
   {
      getDelegate().include(dmo, fields);
   }
   
   /**
    * Specifies the fields excluded from a record retrieval.
    *
    * @param   dmo
    *          DMO proxy which defines the buffer for which the fields are specified.
    * @param   fields
    *          The fields excluded from a record retrieval. If no fields are specified, complete
    *          records are retrieved. No subscripts can be specified for extent fields.
    */
   public void exclude(DataModelObject dmo, String ... fields)
   {
      getDelegate().exclude(dmo, fields);
   }

   /**
    * Get a list of all buffers in this query.
    * 
    * @return    The list of buffers.
    */
   @Override
   public RecordBuffer[] getRecordBuffers()
   {
      RecordBuffer[] bufs = new RecordBuffer[buffers.size()];
      for (int i = 0; i < bufs.length; i++)
      {
         bufs[i] = ((BufferReference) buffers.get(i)).buffer();
      }
      return bufs;
   }
   
   /**
    * Test whether the OFF-END event occurred and if so, fire the callback if one is defined.  
    */
   private void maybeFireCallback()
   {
      if (!offEnd && getDelegate()._isOffEnd())
      {
         offEnd = true;
         
         if (getDataSet() != null && callback != null)
         {
            invokeCallback(asHandle(), this.callback);
         }
      }
   }
   
   /**
    * Add the buffers associated with the given query to this QUERY's buffer list.
    * <p>
    * Will be a no-op when this is a {@link #dynamic} query. 
    * 
    * @param   query
    *          The P2J query from which the buffers are loaded.
    * @param   clear
    *          When <code>true</code>, it will clear the {@link #buffers} list and the predicate.
    */
   private void addBuffers(Joinable query, boolean clear)
   {
      if (dynamic)
      {
         return;
      }
      
      if (clear)
      {
         resetQuery();
      }
      
      for (RecordBuffer buf : query.getRecordBuffers())
      {
         this.buffers.add((Buffer) buf.getDMOProxy());
      }
   }
   
   /**
    * Identify the buffer which matches the given buffer name. Use an instance of the
    * {@code BufferManager} to identify the proper buffer.
    * 
    * @param   bm
    *          An instance of the {@code BufferManager}. This can be {@code null}, case in which
    *          it will be initialized with a buffer manager from the local context.
    * @param   bufName
    *          The buffer name which should be used to identify the searched buffer.
    * @param   bufIdx
    *          The index of the buffer inside the query, such that in case the buffer
    *          searching fails, it will prompt and error indicating the buffer index.
    *          
    * @return  A search buffer instance according to the provide name, or null if no buffer was found.
    */
   private Buffer parseBuffer(BufferManager bm, String bufName, int bufIdx)
   {
      if (bm == null)
      {
         bm = BufferManager.get();
      }
      
      Buffer crtBuff;
      bufName = TextOps.rightTrimNative(bufName);
      
      RecordBuffer rb = bm.lookupByName(bufName);
      if (rb != null)
      {
         crtBuff = (Buffer) rb.getDMOProxy();
      }
      else
      {
         ErrorManager.recordOrShowError(7319, Integer.toString(bufIdx));
         // ADD/SET-BUFFERS argument <argnumber> was invalid or not found.
         return null;
      }
      
      return crtBuff;
   }
   
   /**
    * Check if the resource referenced by given handle is a valid {@link Buffer}.
    * 
    * @param   h
    *          The handle to be checked.
    * @param   idx
    *          The index of this handle in a {@link #setBuffers} call.
    *           
    * @return  <code>true</code> if the handle is valid and the referrent is a {@link Buffer}.
    */
   private boolean validBuffer(handle h, int idx)
   {
      boolean valid = h._isValid() && h.getResource() instanceof Buffer;
      
      if (!valid)
      {
         final String errMsg = "ADD/SET-BUFFERS argument %d was invalid or not found";
         
         ErrorManager.recordOrShowDatabaseError(7319, String.format(errMsg, idx), false, false);
      }
      
      return valid;
   }
   
   /**
    * Check if a buffer can be added to this query.
    * 
    * @return   <code>true</code> if a buffer can be added.
    */
   private boolean canAddBuffer()
   {
      if (!dynamic)
      {
         final String errMsg = "ADD/SET-BUFFERS may not be used on static query %s";
         
         ErrorManager.recordOrShowDatabaseError(7317, String.format(errMsg, qname), false, false);
      }
      
      return dynamic;
   }
   
   /**
    * Check if the query is opened. If is not open, an error message is displayed and an ERROR
    * condition is raised. If the query is forward-only, then it is not scrolling and another
    * ERROR condition is raised.
    * 
    * @return   <code>true</code> if the query is not closed and not forward-only.
    */
   private boolean canReposition()
   {
      // TODO: the rowid is evaluated before checking if the query is closed or not!
      
      if (closed)
      {
         final String errMsg = "Cannot reposition on query %s, which is not opened";
         
         if (dynamic || dynamicDelegate)
         {
            ErrorManager.recordOrShowError(3163, String.format(errMsg, qname), false, false);
         }
         else
         {
            ErrorManager.recordOrThrowError(3163, String.format(errMsg, qname), false, false);
         }
      }
      
      if (forwardOnly)
      {
         final String errMsg = "Cannot reposition on query %s which is not defined as SCROLLING";
         
         ErrorManager.recordOrThrowError(3164, String.format(errMsg, qname), false, false);
         
         return false;
      }
      
      return true;
   }

   /**
    * Check if the query is opened. If is not open, an error message is displayed (but no error
    * recorded).
    * 
    * @return   <code>true</code> if the query is not closed.
    */
   private boolean canGet()
   {
      if (closed)
      {
         final String errMsg = "Cannot run GET methods on query %s until it is opened";
         
         ErrorManager.recordOrShowDatabaseError(7313, String.format(errMsg, qname), false, false);
      }
      
      return !closed;
   }

   /**
    * Check if the query can be advanced via GET-FIRST.
    * 
    * @return   <code>true</code> if the query can be advanced via GET-FIRST.
    */
   private boolean canGetFirst()
   {
      if (forwardOnly && advanced)
      {
         final String errMsg =
            "Cannot move Query %s back to FIRST when FORWARD-ONLY or -noautoreslist enabled";
         
         if (dynamic || dynamicDelegate)
         {
            ErrorManager.recordOrShowError(12394, String.format(errMsg, qname), false, false);
         }
         else
         {
            ErrorManager.recordOrThrowError(12394, String.format(errMsg, qname), false, false);
         }
         
         return false;
      }
      
      return true;
   }

   /**
    * Check if the query is opened. If is not open, an error message is displayed (but no error
    * recorded).
    * 
    * @return   <code>true</code> if the query is not closed.
    */
   private boolean canGetStmt()
   {
      if (closed)
      {
         final String errMsg = "Cannot Get on query %s which is not opened";
         
         if (dynamic || dynamicDelegate)
         {
            ErrorManager.recordOrShowError(3159, String.format(errMsg, qname), false, false);
         }
         else
         {
            ErrorManager.recordOrThrowError(3159, String.format(errMsg, qname), false, false);
         }
         
      }
      
      return !closed;
   }

   /**
    * Check if the GET-LAST or GET-FIRST can be executed.
    * 
    * @return   <code>true</code> if not in forward-only mode.
    */
   private boolean canLastOrPrev()
   {
      if (forwardOnly)
      {
         final String errMsg =
          "Cannot LAST or PREV Query %s when FORWARD-ONLY or -noautoreslist  or BREAK BY enabled";
         
         if (dynamic || dynamicDelegate)
         {
            ErrorManager.recordOrShowError(12393, String.format(errMsg, qname), false, false);
         }
         else
         {
            ErrorManager.recordOrThrowError(12393, String.format(errMsg, qname), false, false);
         }
      }
      
      return !forwardOnly;
   }

   /**
    * Assign a <code>P2JQuery</code> instance as this container's active
    * delegate query.  Set any deferred state which has been set for the
    * wrapper, such as scrollability and whether delegate should error out on
    * failed first/last/unique retrievals.
    *
    * @param   delegate
    *          New delegate query.
    */
   private void assignImpl(P2JQuery delegate)
   {
      assignImpl(delegate, true);
   }
   
   /**
    * Assign a <code>P2JQuery</code> instance as this container's active
    * delegate query.  Set any deferred state which has been set for the
    * wrapper, such as scrollability and whether delegate should error out on
    * failed first/last/unique retrievals.
    *
    * @param   delegate
    *          New delegate query.
    * @param   open
    *          <code>true</code> if the query is considered to be open.
    */
   private void assignImpl(P2JQuery delegate, boolean open)
   {
      if (!closed && this.delegate != null)
      {
         close();
      }
      
      this.originalQueryType = null;
      this.delegate = delegate;
      
      delegate.setForwardOnly(forwardOnly);
      
      if (scrolling)
      {
         delegate.setScrolling();
      }
      
      if (indexedReposition)
      {
         setDelegateIndexedReposition();
      }
      
      delegate.setForceDatabaseJoin(logical.of(this.forceDatabaseJoin));
      delegate.setStandalone(false);
      delegate.setBrowsed(browsed);
      
      if (browsed)
      {
         skipDeletedRecordDisposition = false;
      }
      delegate.setSkipDeletedRecord(logical.of(skipDeletedRecordDisposition));
      delegate.setErrorIfNull(errorIfNull);
      
      if (browsed)
      {
         fetchOnReposition = true;
      }
      delegate.setFetchOnReposition(fetchOnReposition);
      
      Iterator<RepositionListener> iter = repoListeners.iterator();
      while (iter.hasNext())
      {
         RepositionListener next = iter.next();
         delegate.addRepositionListener(next);
      }
      
      this.closed = !open;
   }
   
   /**
    * Convenience method to access the delegate query as an instance of
    * <code>CompoundQuery</code>.
    *
    * @return  Delegate query, cast to a <code>CompoundQuery</code>.
    *
    * @throws  IllegalStateException
    *          if the query delegate is not an instance of
    *          <code>CompoundQuery</code>.
    */
   private CompoundQuery compoundDelegate()
   {
      try
      {
         return (CompoundQuery) delegate;
      }
      catch (ClassCastException exc)
      {
         throw new IllegalStateException(
            "Expected compound query delegate;  found " +
            Utils.getUnqualifiedName(delegate.getClass()));
      }
   }
   
   /**
    * Convenience method to access the delegate query as an instance of
    * <code>PreselectQuery</code>.
    *
    * @return  Delegate query, cast to a <code>PreselectQuery</code>.
    *
    * @throws  IllegalStateException
    *          if the query delegate is not an instance of
    *          <code>PreselectQuery</code>.
    */
   private PreselectQuery preselectDelegate()
   {
      try
      {
         return (PreselectQuery) delegate;
      }
      catch (ClassCastException exc)
      {
         throw new IllegalStateException(
            "Expected preselect query delegate;  found " +
            Utils.getUnqualifiedName(delegate.getClass()));
      }
   }
   
   /**
    * Convenience method to access the delegate query as an instance of
    * <code>PresortDelegate</code>.
    *
    * @return  Delegate query, cast to a <code>PresortDelegate</code>.
    *
    * @throws  IllegalStateException
    *          if the query delegate is not an instance of
    *          <code>PresortDelegate</code>.
    */
   private PresortDelegate presortDelegate()
   {
      try
      {
         return (PresortDelegate) delegate;
      }
      catch (ClassCastException exc)
      {
         throw new IllegalStateException(
            "Expected presort query delegate;  found " +
            Utils.getUnqualifiedName(delegate.getClass()));
      }
   }
   
   /**
    * Convenience method to access the delegate query as an instance of
    * <code>RandomAccessQuery</code>.
    *
    * @return  Delegate query, cast to a <code>RandomAccessQuery</code>.
    *
    * @throws  IllegalStateException
    *          if the query delegate is not an instance of
    *          <code>RandomAccessQuery</code>.
    */
   private RandomAccessQuery randomAccessDelegate()
   {
      try
      {
         return (RandomAccessQuery) delegate;
      }
      catch (ClassCastException exc)
      {
         throw new IllegalStateException(
            "Expected random access query delegate;  found " +
            Utils.getUnqualifiedName(delegate.getClass()));
      }
   }
   
   /**
    * Unregister this wrapper from the list of related queries for all participating buffers.
    * If any buffer is detected to be deleted (not valid or its delete operation is in progress,
    * it is removed from the buffer list).
    */
   private void unregisterBufferRelatedQueries()
   {
      List<Buffer> toDelete = new ArrayList<>();
      
      for (int i = 0; i < buffers.size(); i++)
      {
         Buffer buffer = buffers.get(i);
         BufferImpl bufImpl = (BufferImpl) buffer;
         RecordBuffer recordBuffer = bufImpl.buffer();
         recordBuffer.unregisterRelatedQuery(this);
         
         // remove the buffer if it was deleted or its delete operation is in progress
         if (!bufImpl.valid() || bufImpl.isDeleting())
         {
            toDelete.add(buffer);
         }
      }
      
      buffers.removeAll(toDelete);
   }
   
   /**
    * Convenience method to access the current delegate query.
    *
    * TODO: this is a private method just returning a private member. Should be replaced with direct access which is much faster.
    *
    * @return  Delegate query assigned to this wrapper by business logic, or the default delegate query.
    */
   private P2JQuery getDelegate()
   {
      return delegate;
   }
   
   /**
    * Get legacy query name.
    *
    * @return legacy query name.
    */
   public String getName()
   {
      return qname;
   }
   
   /**
    * Release the buffers. The call is forwarded to {@code delegate} query.
    */
   @Override
   public void releaseBuffers()
   {
      delegate.releaseBuffers();
   }
   
   /**
    * Adds a new constraint term to the where predicate of this query, effectively filtering out
    * any rows whose referenced field does not match the requested value. Semantically, the query
    * will select rows that match
    * <p>
    * {@code new-where := (fr = val) AND (old-query)}.
    * <p>
    * Note: The constraints are exclusive meaning that if constraints will be added for same
    * field of same buffer, the query will return an empty result because the field cannot be at
    * the same time equals to two different values.
    * <p>
    * Use {@link #clearDynamicFilters} to clean all dynamically added criteria and restore the
    * sorting order of the query to its original form.
    *
    * @param   fr
    *          A reference to field used as filtering criterion. Only the rows that matches the
    *          specified value for this field will be selected. Must not be {@code null}. 
    * @param   val
    *          The filtering value for this constraint. Can be {@code null} or {@code unknown}, in
    *          which case the SQL {@code null} value will be assumed. In this case the predicate
    *          will look like:
    *           <p>
    *          {@code new-where := (fr IS  NULL) AND (old-query)}
    * @param   format
    *          The format to be used when comparing values. The reason for this parameter is that
    *          for some datatype (ex: {@code decimal}) the on-screen value can be different from
    *          the database (because of rounding).
    *
    * @return  {@code true} if the filtering constraint was successfully added. If the field
    *          reference is not related to the buffer(s) of this query, {@code false} is returned.
    */
   @Override
   public boolean addDynamicFilter(FieldReference fr, BaseDataType val, String format)
   {
      if (fr == null)
      {
         return false;
      }
      return getDelegate().addDynamicFilter(fr, val, format);
   }
   
   /**
    * Clears any dynamically filters added at runtime. The query predicate will be restored to its
    * form from generated at conversion time. 
    */
   @Override
   public void clearDynamicFilters()
   {
      getDelegate().clearDynamicFilters();
   }
   
   /**
    * Clears any dynamically sort criteria added at runtime. The query sort order will be restored
    * to its form from generated at conversion time.
    */
   public void clearDynamicSorts()
   {
      if (originalQueryType != null && originalQueryType == AdaptiveQuery.class)
      {
         PreselectQuery pq = (PreselectQuery) getDelegate();
         
         AdaptiveQuery aq = new AdaptiveQuery();
         
         // initialize to create components array
         assign(aq.initialize());
         
         // add to components
         ArrayList<QueryComponent> components = pq.components();
         for (int i = 0; i < components.size(); i++)
         {
            QueryComponent comp = components.get(i);
            addBuffer((Buffer) comp.getBuffer().getDMOProxy(), true);
            aq.addComponent(comp);
         }
         
         return;
      }
      
      P2JQuery del = getDelegate();
      if (del instanceof PreselectQuery)
      {
         ((PreselectQuery) del).clearDynamicSortCriteria();
      }
      else if (del instanceof PresortDelegate)
      {
         ((PresortDelegate) del).clearDynamicSortCriteria();
      }
      else
      {
         return; // no sorted, nothing to reset
      }
   }
   
   /**
    * Adds a new sorting criterion as the strongest criterion for sorting the result of this
    * query. The other criteria remain queued, but with lower priority.
    * <p>
    * Use {@link #clearDynamicSorts} to clean all dynamically added criteria and restore the
    * sorting order of the query to its original form.
    *
    * @param   fr
    *          A reference to field used as new strongest criterion. The current criteria will
    *          be kept, but with lower priority.
    * @param   asc
    *          The direction of sorting for this criterion. Use {@code true} for ascending sort
    *          and {@code false} for descending sorting.
    */
   public void addDynamicSort(FieldReference fr, boolean asc)
   {
      addDynamicSort(new FieldReference[]{fr}, new boolean[]{asc});
   }
   
   /**
    * Adds new sorting criteria as the most coarse set of criteria for sorting the result of this
    * query. The other criteria remain queued, but with lower priority. 
    * <p>
    * Use {@link #clearDynamicSorts} to clean all dynamically added criteria and restore the
    * sorting order of the query to its original form.
    *
    * @param   fieldReferences
    *          References to fields used as new most coarse criteria. The current criteria will
    *          be kept, but with lower priority. Inside the array criteria are positioned from
    *          the most coarse to the most granular.
    * @param   asc
    *          Direction of sorting for the new criteria. Use {@code true} for ascending sort
    *          and {@code false} for descending sorting. Inside the array directions are
    *          positioned from the most coarse criterion to the most granular.
    */
   public void addDynamicSort(FieldReference[] fieldReferences, boolean[] asc)
   {
      P2JQuery del = getDelegate();
      if (del instanceof PresortDelegate)
      {
         for (int i = fieldReferences.length - 1; i >= 0; i--)
         {
            ((PresortDelegate) del).addDynamicSortCriterion(fieldReferences[i], asc[i]);
         }
      }
      else if (del instanceof CompoundQuery)
      {
         PresortCompoundQuery pcq = new PresortCompoundQuery();
         assign(pcq.initialize());
         for (int i = fieldReferences.length - 1; i >= 0; i--)
         {
            pcq.addDynamicSortCriterion(fieldReferences[i], asc[i]);
         }

         CompoundQuery cq = (CompoundQuery) del;
         ArrayList<CompoundComponent> originalComponents = cq.getOriginalComponents();
         for (int i = 0; i < originalComponents.size(); i++)
         {
            CompoundComponent comp = originalComponents.get(i);
            addComponent(comp.getQuery(), comp.getIteration(), comp.isOuter());
         }
      }
      else if (del instanceof AdaptiveQuery)
      {
         AdaptiveQuery aq = (AdaptiveQuery) del;    
         PreselectQuery pq = new PreselectQuery();
         
         // initialize to create components array
         assign(pq.initialize(aq.getSortPhrase()));
         
         originalQueryType = AdaptiveQuery.class;

         // add to components
         ArrayList<QueryComponent> components = aq.components();
         for (int i = 0; i < components.size(); i++)
         {
            QueryComponent comp = components.get(i);
            addBuffer((Buffer) comp.getBuffer().getDMOProxy(), true);
            pq.addComponent(comp);
         }
         
         // add dynamic sort criteria AFTER adding the components
         for (int i = fieldReferences.length - 1; i >= 0; i--)
         {
            pq.addDynamicSortCriterion(fieldReferences[i], asc[i]);
         }
      }
      else if (del instanceof PreselectQuery)
      {
         for (int i = fieldReferences.length - 1; i >= 0; i--)
         {
            ((PreselectQuery) del).addDynamicSortCriterion(fieldReferences[i], asc[i]);
         }
      }
      else
      {
         if (LOG.isLoggable(Level.WARNING))
         {
            LOG.warning("Failed to add dynamic sorting for " + del.getClass());
         }
      }
   }

   /**
    * Adds a listener to be notified about the query wrapper events. The events are related to the wrapper
    * rather to the delegate. E.g. query open event is fired when the currently assigned delegate is about to
    * be opened, and the delegate may change over time.
    *
    * @param   listener
    *          The listener to be notified.
    */
   public void addQueryWrapperListener(QueryWrapperListener listener)
   {
      if (wrapperListeners == null)
      {
         wrapperListeners = new HashSet<>();
      }

      wrapperListeners.add(listener);
   }

   /**
    * Remove a listener from being notified about the query wrapper events.
    *
    * @param   listener
    *          The listener to be removed.
    */
   public void removeQueryWrapperListener(QueryWrapperListener listener)
   {
      if (wrapperListeners == null)
      {
         return;
      }
      
      wrapperListeners.remove(listener);
   }
   
   /**
    * Check if the resource can veto the delete or not, before attempting the {@link #delete()} call.
    *
    * @param    ref
    *           The exact handle holding the reference, on which the delete is attempted.
    * @param    explicit
    *           Flag indicating this is called via <code>DELETE OBJECT</code> from the application.
    *
    * @return   <code>false</code> if the delete is vetoed.
    */
   @Override
   public boolean allowDelete(handle ref, boolean explicit)
   {
      if (ref == null || !ref._isValid() || !(ref.getResource() instanceof QueryWrapper))
      {
         return super.allowDelete(ref, explicit);
      }
      
      QueryWrapper query = (QueryWrapper) ref.getResource();
      boolean allow = query.isExplicit() || !explicit;
      if (!allow)
      {
         ErrorManager.recordOrShowError(12349);
         // Cannot delete a dataset relation auto-generated query. (12349)
      }
      
      return allow;
   }
   
   /**
    * Test whether this is an explicit query. The implicit queries cannot be deleted in a 4GL program.
    * 
    * @return  {@code true} if this is a normal (explicitly) created query. 
    */
   boolean isExplicit()
   {
      return explicit;
   }
   
   /**
    * Mark this query as implicit. By default, all queries are explicit. The implicit queries are
    * queries managed automatically for DataSources. They are created and deleted without programmer
    * interference.
    */
   void setImplicit()
   {
      this.explicit = false;
   }
   
   /**
    * Notify query wrapper event listeners that the query is about to be opened.
    */
   void notifyBeforeOpenListeners()
   {
      if (wrapperListeners == null)
      {
         return;
      }
      
      for (QueryWrapperListener listener : wrapperListeners)
      {
         listener.beforeQueryOpen();
      }
   }
   
   /**
    * Instruct dynamic conversion to use the list of 'parent' buffers of {@code datasetBuffer} as substitution
    * buffers. These are not the main buffers the query is iterating but may appear in SUBST nodes (as
    * substitutions).
    *
    * @param   datasetBuffer
    *          The {@code Buffer} this query is used to populate  in a {@code fill()} operation. If this is
    *          not a database buffer or the buffer is a top-level buffer, no substitution buffers are added. 
    */
   void setSubstitutionBuffers(Buffer datasetBuffer)
   {
      substBuffers = null;
      
      DataSet dataSet = (DataSet) datasetBuffer.dataSet().getResource();
      if (dataSet == null)
      {
         return;
      }
      
      substBuffers = new ArrayList<>();
      substBuffers.add(datasetBuffer);
      
      List<DataRelation> parentRelations = dataSet.getRelations(datasetBuffer, false, true, false);
      if (!parentRelations.isEmpty())
      {
         for (DataRelation rel : parentRelations)
         {
            substBuffers.add(rel.getParentBuffer().unwrapBuffer());
         }
      }
   }
   
   /**
    * Instruct dynamic conversion to add a list of substitution buffers. These are not the main
    * buffers the query is iterating but may appear in SUBST nodes (as substitutions).
    * 
    * @param   substs
    *          A list of node that the query may use in substitution nodes.
    */
   void setSubstitutionBuffers(Buffer... substs)
   {
      substBuffers = Arrays.asList(substs);
   }

   /**
    * Notify all registered listeners the query is deleted.
    */
   protected void notifyQueryDeleted()
   {
      if (repoListeners != null)
      {
         Iterator<RepositionListener> iter = repoListeners.iterator();
         while (iter.hasNext())
         {
            RepositionListener next = iter.next();
            next.queryDeleted();
         }
      }
   }
   
   /**
    * Invokes a callback procedure or a callback method. The callback procedure/method must have an
    * {@code INPUT} parameter of type {@code DATASET} or {@code DATASET-HANDLE}. The passed parameter is this
    * {@code DataSet} object.
    *
    * @param   cbd
    *          A {@code CallbackData} object holding the data necessary for invocation. May be {@code null},
    *          in which case this method will silently return {@code yes} even though nothing is performed.
    * @param   self
    *          The object on which the event is applied (buffer or dataset).
    *
    * @return  {@code true} if no errors were encountered during execution. 
    */
   protected boolean invokeCallback(handle self, CallbackData cbd)
   {
      if (cbd == null)
      {
         return true; // yep, nothing to do here
      }
      
      try
      {
         ErrorManager.setSilent(false);
         
         SelfManager.pushSelf(self);
         
         // reference already assumes input-output, do not emit append
         DataSetParameter dsp = new DataSetParameter(getDataSet(), ParameterOption.BY_REFERENCE);
         if (cbd.getObject() != null)
         {
            // TODO:
            // Method '<methodname>' for callback must be valid public method. (13452)
            
            ObjectOps.invokeStandalone(cbd.getObject(), cbd.getTarget(), "I", dsp);
         }
         else if (cbd.getProcedure() != null && !cbd.getProcedure().isUnknown())
         {
            InvokeConfig callSite = cbd.getCallSite();
            InvokeConfig cfg = callSite == null ? new InvokeConfig() : callSite.clone();
            cfg.setTarget(cbd.getTarget())
               .setInHandle(cbd.getProcedure())
               .setModes("I")
               .setArguments(dsp)
               .executeForResource(this);
         }
         
         // NOTE: sometimes the method return *NO* even if the callback was successfully called
         return true;
      }
      catch (Exception e)
      {
         LOG.severe("", e);
         return false;
      }
      finally
      {
         SelfManager.popSelf();
         
         // Do not restore silent-mode!
      }
   }
   
   /**
    * Obtains the {@code Dataset} of the first buffer of this query, if this is defined.
    * 
    * @return  the {@code Dataset} of the first buffer of this query, if this is defined.
    */
   private DataSet getDataSet()
   {
      DataSet ds = null;
      if (buffers != null && buffers.size() > 0)
      {
         BufferImpl buffer = (BufferImpl) buffers.get(0);
         if (buffer.isAfterBuffer())
         {
            ds = buffer._dataSet();
         }
      }
      return ds;
   }
   
   /**
    * Test whether a string is a valid CALLBACK name for a {@code DataSet Query}. This method is responsible
    * for raising the 12352 error if the name specified is unknown or not {@code OFF-END} - the only supported
    * event for dataset queries.
    *
    * @param   someName
    *          The name to test.
    *
    * @return  {@code true} only if {@code someName} is equals to "OFF-END".
    */
   private static boolean isCallbackName(String someName)
   {
      if (!OFF_END_EVENT.equalsIgnoreCase(someName))
      {
         ErrorManager.recordOrShowError(12352, someName != null ? someName : "");
         // Argument <name> to query callback method must be a valid query event name such as OFF-END
         return false;
      }
      
      return true;
   }

   /**
    * Helper for making delegate query indexed reposition while checking the eligibility.
    */
   private void setDelegateIndexedReposition()
   {
      if (!scrolling)
      {
         final String errMsg = "MAX-ROWS, INDEXED-REPOSITION, etc. require query %s " +
                               "to be defined with SCROLLING.";
         ErrorManager.noRecordOrThrowError(String.format(errMsg, qname));
      }
      
      if (getDelegate().isNativelyPreselect())
      {
         // silently ignore the indexed reposition optimization
      }
      
      if (delegate != null)
      {
         getDelegate().setIndexedReposition();
      }
   }
   
   /**
    * A no-op implementation of <code>P2JQuery</code> which is used as the
    * default delegate for the enclosing <code>QueryWrapper</code>.  This
    * implementation behaves as a query which returns no results would,
    * except that its <code>isValid</code> method returns <code>false</code>,
    * as an indication that it is a "fake" query for those callers to whom
    * this information is relevant.
    */
   private static class DefaultDelegate
   implements P2JQuery
   {
      /**
       * No-op.
       */
      @Override
      public void clearResults()
      {
      }
      
      /**
       * No-op.
       */
      public void setScrolling()
      {
      }
      
      /**
       * Indicate whether this query was defined as SCROLLING.
       *
       * @return  <code>false</code>.
       */
      public boolean isScrolling()
      {
         return false;
      }
      
      /**
       * No-op.
       *
       * @param   value
       *          <code>true</code> to enable forward-only, <code>false</code> to disable it.
       */
      public void setForwardOnly(boolean value)
      {
      }
      
      /**
       * Method that returns a default value for the forwardOnly flag.
       * 
       * @return  <code>true</code> if forward-only is enabled, <code>false</code> otherwise.
       */
      public boolean isForwardOnly()
      {
         return false;
      }
      
      /**
       * No-op.
       */
      @Override
      public void setForceDatabaseJoin(logical forceDatabaseJoin)
      {
         
      }
      
      /**
       * Indicate whether this query should enforce a database join if possible.
       *
       * @return  <code>false</code>.
       */
      @Override
      public logical isForceDatabaseJoin()
      {
         return logical.of(false);
      }
      
      /**
       * No-op.
       */
      @Override
      public void setIndexedReposition()
      {
         
      }
      
      /**
       * Indicate whether this query is optimized using indexed reposition.
       *
       * @return  <code>false</code>.
       */
      @Override
      public boolean isIndexedReposition()
      {
         return false;
      }
      
      /**
       * No-op.
       */
      public void open()
      {
      }
      
      /**
       * No-op.
       */
      public void close()
      {
      }
      
      /**
       * Get the number of tables joined by this query.
       * 
       * @return  0.
       */
      public int getTableCount()
      {
         return 0;
      }
      
      /**
       * Get all the off-end listeners associated with this query.
       * 
       * @return  the off-end listeners associated with this query.
       */
      public ArrayList<QueryOffEndListener> getOffEndListeners()
      {
         return null;
      }
      
      /**
       * Add one or more buffers to the list of those which this query references externally. These
       * typically will be buffers referenced by converted CAN-FIND expressions embedded in the
       * query's HQL expression, which are not the primary buffers associated with the query.
       * <p>
       * No-op.
       * 
       * @param   dmos
       *          One or more external buffers.
       * 
       * @return  {@code null}.
       */
      public P2JQuery addExternalBuffers(DataModelObject... dmos)
      {
         return null;
      }
      
      /**
       * Adds an alternative execution query, for the multi-tenant case in which the CAN-FIND nested buffer and
       * the main buffer of query component do not belong to same physical database.
       * <p>
       * This method will be generated only in case of multi-tenant projects, in the condition above-mentioned.
       *
       * @param   where
       *          FQL where clause.  May be {@code null}.
       * @param   whereExpr
       *          Client-side where clause expression. May be {@code null} but this is probably caused by an
       *          incorrect conversion.
       * @param   sort
       *          The sort order.
       * @param   args
       *          Substitution parameters for FQL queries. These will be used if not overridden by a record
       *          retrieval method.
       *
       * @return  Self object so that the call to this method can be optionally chained with the constructor.
       */
      @Override
      public RandomAccessQuery setMultiTenantAlternative(String where,
                                                         Supplier<logical> whereExpr,
                                                         String sort,
                                                         Object[] args)
      {
         return null;
      }
      
      /**
       * Adds an alternative execution query, for the multi-tenant case in which the CAN-FIND nested buffer
       * and the main buffer of query component do not belong to same physical database.
       * <p>
       * This method will be generated only in case of multi-tenant projects, in the condition above-mentioned.
       *
       * @param   where
       *          FQL where clause.  May be {@code null}.
       * @param   whereExpr
       *          Client-side where clause expression. May be {@code null} but this is probably caused by an
       *          incorrect conversion.
       * @param   sort
       *          The sort order.
       *
       * @return  {@code null}.
       */
      @Override
      public P2JQuery setMultiTenantAlternative(String where, Supplier<logical> whereExpr, String sort)
      {
         return null;
      }
      
      /**
       * No-op.
       *
       * @param   browsed
       *          Not used.
       */
      public void setBrowsed(boolean browsed)
      {
      }
      
      /**
       * Is this query associated with a browse widget or not?
       *
       * @return  <code>false</code>.
       */
      public boolean isBrowsed()
      {
         return false;
      }
      
      /**
       * No-op.
       *
       * @param   errorIfNull
       *          Not used.
       */
      public void setErrorIfNull(boolean errorIfNull)
      {
      }
      
      /**
       * No-op.
       *
       * @param   accum
       *          Not used.
       */
      public void addAccumulator(Accumulator accum)
      {
      }
      
      /**
       * No-op.
       *
       * @param   accum
       *          Not used.
       * @param   deferred
       *          Not used.
       */
      public void addAccumulator(Accumulator accum, boolean deferred)
      {
      }
      
      /**
       * No-op.
       */
      public boolean first()
      {
         return false;
      }
      
      /**
       * No-op.
       *
       * @param   lockType
       *          Not used.
       */
      public boolean first(LockType lockType)
      {
         return false;
      }
      
      /**
       * No-op.
       */
      public boolean last()
      {
         return false;
      }
      
      /**
       * No-op.
       *
       * @param   lockType
       *          Not used.
       */
      public boolean last(LockType lockType)
      {
         return false;
      }
      
      /**
       * No-op.
       */
      public boolean next()
      {
         return true;
      }
      
      /**
       * No-op.
       *
       * @param   lockType
       *          Not used.
       */
      public boolean next(LockType lockType)
      {
         return true;
      }
      
      /**
       * No-op.
       */
      public boolean previous()
      {
         return false;
      }
      
      /**
       * No-op.
       *
       * @param   lockType
       *          Not used.
       */
      public boolean previous(LockType lockType)
      {
         return false;
      }
      
      /**
       * No-op.
       */
      public boolean unique()
      {
         return false;
      }
      
      /**
       * No-op.
       *
       * @param   lockType
       *          Not used.
       */
      public boolean unique(LockType lockType)
      {
         return false;
      }
      
      /**
       * No-op.
       */
      public boolean current()
      {
         return false;
      }
      
      /**
       * No-op.
       *
       * @param   lockType
       *          Not used.
       */
      public boolean current(LockType lockType)
      {
         return false;
      }
      
      /**
       * Indicate whether a request to find the first result of this query would
       * succeed or fail.
       * <p>
       * Default substitution arguments and a lock type of <code>NONE</code> are
       * used for this test.
       * 
       * @return  <code>true</code> if the first record exists, else <code>false</code>.
       * 
       * @throws  UnsupportedOperationException
       *          always.
       */
      public logical hasAny()
      {
         throw new UnsupportedOperationException();
      }
      
      /**
       * Indicate whether a request to find the first result of this query would
       * succeed or fail.
       * <p>
       * The specified substitution arguments and a lock type of
       * <code>NONE</code> are used for this test.
       * 
       * @param   values
       *          Query substitution parameters.
       * 
       * @return  <code>true</code> if the first record exists, else <code>false</code>.
       * 
       * @throws  UnsupportedOperationException
       *          always.
       */
      public logical hasAny(Object[] values)
      {
         throw new UnsupportedOperationException();
      }
      
      /**
       * Indicate whether a request to find the first result of this query would
       * succeed or fail.
       * <p>
       * Default substitution arguments and the specified lock type are used for
       * this test.
       * 
       * @param   lockType
       *          Lock type for the query.  This lock is not actually acquired,
       *          only tested for availability.
       * 
       * @return  <code>true</code> if the first record exists, else <code>false</code>.
       * 
       * @throws  UnsupportedOperationException
       *          always.
       */
      public logical hasAny(LockType lockType)
      {
         throw new UnsupportedOperationException();
      }
      
      /**
       * Indicate whether a request to find the first result of this query would
       * succeed or fail.
       * <p>
       * The specified substitution arguments and lock type are used for this
       * test.
       *
       * @param   values
       *          Query substitution parameters.
       * @param   lockType
       *          Lock type for the query.  This lock is not actually acquired,
       *          only tested for availability.
       * 
       * @return  <code>true</code> if the first record exists, else <code>false</code>.
       * 
       * @throws  UnsupportedOperationException
       *          always.
       */
      public logical hasAny(Object[] values, LockType lockType)
      {
         throw new UnsupportedOperationException();
      }
      
      /**
       * Indicate whether this query would produce a unique result.
       * <p>
       * Default substitution arguments and a lock type of <code>NONE</code> are
       * used for this test.
       * 
       * @return  <code>true</code> if any record matching the query's criteria
       *          exists, else <code>false</code>.
       * 
       * @throws  UnsupportedOperationException
       *          always.
       */
      public logical hasOne()
      {
         throw new UnsupportedOperationException();
      }
      
      /**
       * Indicate whether this query would produce a unique result.
       * <p>
       * The specified substitution arguments and a lock type of
       * <code>NONE</code> are used for this test.
       * 
       * @param   values
       *          Query substitution parameters.
       * 
       * @return  <code>true</code> if any record matching the query's criteria
       *          exists, else <code>false</code>.
       * 
       * @throws  UnsupportedOperationException
       *          always.
       */
      public logical hasOne(Object[] values)
      {
         throw new UnsupportedOperationException();
      }
      
      /**
       * Indicate whether this query would produce a unique result.
       * <p>
       * Default substitution arguments and the specified lock type are used for
       * this test.
       * 
       * @param   lockType
       *          Lock type for the query.  This lock is not actually acquired,
       *          only tested for availability.
       * 
       * @return  <code>true</code> if any record matching the query's criteria
       *          exists, else <code>false</code>.
       * 
       * @throws  UnsupportedOperationException
       *          always.
       */
      public logical hasOne(LockType lockType)
      {
         throw new UnsupportedOperationException();
      }
      
      /**
       * Indicate whether this query would produce a unique result.
       * <p>
       * The specified substitution arguments and lock type are used for this
       * test.
       *
       * @param   values
       *          Query substitution parameters.
       * @param   lockType
       *          Lock type for the query.  This lock is not actually acquired,
       *          only tested for availability.
       * 
       * @return  <code>true</code> if any record matching the query's criteria
       *          exists, else <code>false</code>.
       * 
       * @throws  UnsupportedOperationException
       *          always.
       */
      public logical hasOne(Object[] values, LockType lockType)
      {
         throw new UnsupportedOperationException();
      }
      
      /**
       * Default implementation which reports query is not set to fetch the
       * next record after a reposition.
       *
       * @return  <code>false</code>.
       */
      public boolean isFetchOnReposition()
      {
         return false;
      }
      
      /**
       * No-op.
       *
       * @param   enable
       *          Not used.
       */
      public void setFetchOnReposition(boolean enable)
      {
      }
   
      /**
       * No-op.
       *
       * @param   listener
       *          Not used.
       */
      public void addRepositionListener(RepositionListener listener)
      {
      }

      /**
       * No-op.
       *
       * @param   listener
       *          Not used.
       */
      public void removeRepositionListener(RepositionListener listener)
      {
      }
      
      /**
       * No-op.
       *
       * @param   id
       *          Not used.
       */
      public void repositionByID(recid id)
      {
      }
      
      /**
       * No-op.
       *
       * @param   id1
       *          Not used.
       * @param   joinIDs
       *          Not used.
       */
      public void repositionByID(rowid id1, rowid... joinIDs)
      {
      }
      
      /**
       * No-op.
       *
       * @param   joinIDs
       *          Not used.
       *
       * @return  Always {@code true}.
       */
      public boolean repositionByID(Long... joinIDs)
      {
         return true;
      }
      
      /**
       * No-op.
       *
       * @param   row
       *          Not used.
       */
      public void reposition(NumberType row)
      {
      }
      
      /**
       * No-op.
       *
       * @param   row
       *          Not used.
       */
      public void reposition(int row)
      {
      }
      
      /**
       * No-op.
       *
       * @param   rows
       *          Not used.
       */
      public boolean forward(NumberType rows)
      {
         return false;
      }
      
      /**
       * No-op.
       *
       * @param   rows
       *          Not used.
       */
      public boolean forward(int rows)
      {
         return false;
      }
      
      /**
       * No-op.
       *
       * @param   rows
       *          Not used.
       */
      public boolean backward(NumberType rows)
      {
         return false;
      }
      
      /**
       * No-op.
       *
       * @param   rows
       *          Not used.
       */
      public boolean backward(int rows)
      {
         return false;
      }
      
      /**
       * Default implementation which reports unknown value to indicate a
       * closed query.
       *
       * @return  unknown value.
       */
      public integer size()
      {
         return (new integer());
      }
      
      /**
       * Default implementation which reports unknown value as the current
       * row to indicate an empty results list.
       *
       * @return  Unknown value.
       */
      public integer currentRow()
      {
         return currentRowImpl();
      }
      
      /**
       * Default implementation which reports unknown value as the current
       * row to indicate an empty results list.
       *
       * @return  Unknown value.
       */
      public integer currentRowImpl()
      {
         return (new integer());
      }
      
      /**
       * Default implementation which reports the query is off-end.
       *
       * @return  <code>true</code>.
       */
      public logical isOffEnd()
      {
         return (logical.of(true));
      }
      
      /**
       * Default implementation which reports the query is off-end.
       *
       * @return  <code>true</code>.
       */
      public boolean _isOffEnd()
      {
         return true;
      }

      /**
       * Default implementation which reports that the query has the front
       * off-end.
       *
       * @return  {@link OffEnd#FRONT} constant.
       */
      public OffEnd getOffEnd()
      {
         return OffEnd.FRONT;
      }

      /**
       * Indicate whether this query preselects all of its results.
       *
       * @return  <code>false</code>.
       */
      public boolean isPreselect()
      {
         return false;
      }

      /**
       * Indicate whether this query is a preselect query by its nature.
       *
       * @return  <code>true</code>.
       */
      public boolean isNativelyPreselect()
      {
         return false;
      }

      /**
       * No-op.
       * 
       * @param   closed
       *          Not used.
       * @param   error
       *          Not used.
       * @param   targetRepositionRow
       *          Not used.
       */
      public void notifyRepositionListeners(boolean closed,
                                            boolean error,
                                            int targetRepositionRow)
      {
      }

      /**
       * Indicate whether this query stands alone, or is the component of
       * another query, or is wrapped by a query wrapper.
       * 
       * @return  <code>false</code>.
       */
      public boolean isStandalone()
      {
         return false;
      }
      
      /**
       * Change the standalone nature of this query.  A query is standalone by
       * default, but can be changed to non-standalone by the wrapper or
       * container which contains it.
       * <p>
       * This implementation is a no-op.
       * 
       * @param   standalone
       *          <code>true</code> to set query as standalone;
       *          <code>false</code> to set query as contained.
       */
      public void setStandalone(boolean standalone)
      {
      }
      
      /**
       * No-op.
       */
      public void cleanup()
      {
      }

      /**
       * Conversion of GET-BUFFER-HANDLE() method (KW_GET_BUFH).
       *
       * Returns a handle of the first buffer of a query object.
       *
       * @return unknown buffer handle
       */
      public handle bufferHandle()
      {
         return new handle();
      }

      /**
       * Conversion of GET-BUFFER-HANDLE() method (KW_GET_BUFH).
       *
       * Returns a handle of a particular buffer of a query object.
       *
       * @param   bufferName
       *          buffer-name. A CHARACTER expression that evaluates to the name
       *          of a buffer in the query or DataSet object.
       *
       * @return  Unknown buffer handle.
       */
      public handle bufferHandle(String bufferName)
      {
         return (new handle());
      }

      /**
       * Conversion of GET-BUFFER-HANDLE() method (KW_GET_BUFH).
       *
       * Returns a handle of a particular buffer of a query object.
       *
       * @param   bufferName
       *          buffer-name. A CHARACTER expression that evaluates to the name
       *          of a buffer in the query or DataSet object.
       *
       * @return  Unknown buffer handle.
       */
      public handle bufferHandle(character bufferName)
      {
         return (new handle());
      }

      /**
       * Conversion of GET-BUFFER-HANDLE() method (KW_GET_BUFH).
       *
       * Returns a handle of a particular buffer of a query object.
       *
       * @param   bufferSequenceNumber
       *          buffer-sequence-number. An INTEGER that represents the sequence
       *          number of the desired buffer.
       *
       * @return  Unknown buffer handle.
       */
      public handle bufferHandle(int bufferSequenceNumber)
      {
         return (new handle());
      }

      /**
       * Conversion of GET-BUFFER-HANDLE() method (KW_GET_BUFH).
       *
       * Returns a handle of a particular buffer of a query object.
       *
       * @param   bufferSequenceNumber
       *          buffer-sequence-number. An INTEGER that represents the sequence
       *          number of the desired buffer.
       *
       * @return  Unknown buffer handle.
       */
      @Override
      public handle bufferHandle(int64 bufferSequenceNumber)
      {
         return (new handle());
      }

      /**
       * Conversion of QUERY-CLOSE() method (KW_QRY_CLOS).
       *
       * Closes a query object.
       *
       * @return  <code>false</code>.
       */
      public logical queryClose()
      {
         return (logical.of(false));
      }

      /**
       * Conversion of REPOSITION-BACKWARD() method (KW_REPOS_B).
       *
       * Moves a query object's result list pointer backward a particular number
       * of rows.
       *
       * @return  <code>false</code>.
       */
      public logical queryBackward(int rows)
      {
         return (logical.of(false));
      }

      /**
       * Conversion of REPOSITION-BACKWARD() method (KW_REPOS_B).
       *
       * Moves a query object's result list pointer backward a particular number
       * of rows.
       *
       * @return  <code>false</code>.
       */
      public logical queryBackward(NumberType rows)
      {
         return (logical.of(false));
      }

      /**
       * Conversion of REPOSITION-FORWARD() method (KW_REPOS_F).
       *
       * Moves a query object's result list pointer forward a particular number
       * of rows.
       *
       * @return  <code>false</code>.
       */
      public logical queryForward(int rows)
      {
         return (logical.of(false));
      }

      /**
       * Conversion of REPOSITION-FORWARD() method (KW_REPOS_F).
       *
       * Moves a query object's result list pointer forward a particular number
       * of rows.
       *
       * @return  <code>false</code>.
       */
      public logical queryForward(NumberType rows)
      {
         return (logical.of(false));
      }

      /**
       * Conversion of REPOSITION-TO-ROW() method (KW_REPOS_2R).
       *
       * Moves a query object's result list pointer to the row corresponding to the specified
       * sequence number.
       *
       * @param   n
       *          An integer expression representing the sequence number.
       *
       * @return  <code>false</code>.
       */
      public logical queryReposition(int n)
      {
         return (logical.of(false));
      }

      /**
       * Conversion of REPOSITION-TO-ROW() method (KW_REPOS_2R).
       *
       * Moves a query object's result list pointer to the row corresponding to the specified
       * sequence number.
       *
       * @param   n
       *          An integer expression representing the sequence number.
       *
       * @return  <code>false</code>.
       */
      public logical queryReposition(NumberType n)
      {
         return (logical.of(false));
      }

      /**
       * Conversion of REPOSITION-TO-ROWID() method (KW_REPOS_2I).
       *
       * Reposition the cursor such that a request to retrieve the next result
       * will retrieve the result which matches the specified array of primary
       * key IDs.  A request to retrieve the previous result will retrieve the
       * result immediately previous to this, if any, in the results list.
       *
       * @param   id1
       *          A primary key ID, representing the target record (in the case
       *          of a join, this ID is associated with the left-most record in
       *          the join).
       * @param   joinIDs
       *          All remaining primary key IDs, if any, arranged from left to
       *          right to coincide with the records being joined by the
       *          underlying query.
       *
       * @return  <code>false</code>.
       */
      public logical queryRepositionByID(rowid id1, rowid...joinIDs)
      {
         return (logical.of(false));
      }
      
      /**
       * Conversion of REPOSITION-TO-ROWID() method (KW_REPOS_2I).
       *
       * Reposition the cursor such that a request to retrieve the next result
       * will retrieve the result which matches the specified array of primary
       * key IDs.  A request to retrieve the previous result will retrieve the
       * result immediately previous to this, if any, in the results list.
       *
       * @param   id1
       *          A primary key ID, representing the target record (in the case
       *          of a join, this ID is associated with the left-most record in
       *          the join).
       * @param   joinIDs
       *          The list of IDs, starting with the primary key ID representing the target record, while 
       *          all remaining primary key IDs, if any, arranged from left to right to coincide with the records 
       *          being joined by the underlying query.
       *
       * @return  <code>true</code> if REPOSITION-TO-ROWID() succeeds,
       *          else <code>false</code>.
       */
      @Override
      public logical queryRepositionByID(rowid[] joinIDs)
      {
         return logical.FALSE;
      }

      /**
       * Conversion of REPOSITION-TO-ROWID() method (KW_REPOS_2I).
       *
       * Reposition the cursor such that a request to retrieve the next result
       * will retrieve the result which matches the specified array of primary
       * key IDs.  A request to retrieve the previous result will retrieve the
       * result immediately previous to this, if any, in the results list.
       *
       * @param   rowId
       *          A character representation of this rowid.
       *
       * @return  <code>true</code> if REPOSITION-TO-ROWID() succeeds,
       *          else <code>false</code>.
       */
      public logical queryRepositionByID(character rowId)
      {
         return logical.of(false);
      }

      /**
       * Conversion of NUM-RESULTS attribute (KW_NUM_RES).
       *
       * Getter of NUM-RESULTS attribute
       *
       * @return  Unknown value.
       */
      public integer getNumResults()
      {
         return (new integer());
      }

      /**
       * Adds one new buffer to a query object or dynamic DataSet object,
       * without affecting the other buffers, if any. Use the SET-BUFFERS( )
       * method to remove all prior buffers and set all buffers for the object
       * at the same time.
       *
       * @param   bufHandle
       *          A buffer handle to add.
       *
       * @return  <code>false</code>.
       */
      public logical addBuffer(handle bufHandle)
      {
         return (logical.of(false));
      }

      /**
       * Adds one new buffer to a query object or dynamic DataSet object, 
       * without affecting the other buffers, if any. Use the SET-BUFFERS( )
       * method to remove all prior buffers and set all buffers for the object 
       * at the same time.
       * 
       * @param   buf
       *          A buffer to add.
       *
       * @return  <code>false</code>.
       */
      @Override
      public logical addBuffer(Buffer buf)
      {
         return (logical.of(false));
      }

      /**
       * Sets buffers for the query. Any buffers previously added
       * or set are removed. Use the <code>addBuffer()</code> method to add one 
       * buffer to the object, without affecting the other buffers, if any.
       * This method is the equivalent of <code>SET-BUFFERS()</code> method 
       * from 4GL.
       *
       * @param   hBuffers
       *          Variable argument list of buffer handles to be set.
       *          In 4GL, the maximum number of buffers per query is 18.
       *
       * @return  <code>false</code>.
       */
      @Override
      public logical setBuffers(handle... hBuffers)
      {
         return (logical.of(false));
      }

      /**
       * Sets buffers for the query. Any buffers previously added
       * or set are removed. Use the <code>addBuffer()</code> method to add one 
       * buffer to the object, without affecting the other buffers, if any.
       * This method is the equivalent of <code>SET-BUFFERS()</code> method 
       * from 4GL.
       * 
       * @param   bufs
       *          Variable argument list of Buffer to be set.
       *          In 4GL, the maximum number of buffers per query is 18.
       * 
       * @return  true on success
       */
      @Override
      public logical setBuffers(Buffer... bufs)
      {
         return (logical.of(false));
      }

      /**
       * Compiles a predicate (query condition). This method is
       * the equivalent of <code>QUERY-PREPARE()</code> method from 4GL.
       * 
       * @param   predicate
       *          The predicate to be prepared by this query.
       *
       * @return  <code>false</code>.
       */
      @Override
      public logical prepare(String predicate)
      {
         return (logical.of(false));
      }

      /**
       * Compiles a predicate (query condition). This method is
       * the equivalent of <code>QUERY-PREPARE()</code> method from 4GL.
       * 
       * @param   predicate
       *          The predicate to be prepared by this query.
       *
       * @return  <code>false</code>.
       */
      @Override
      public logical prepare(character predicate)
      {
         return (logical.of(false));
      }

      /**
       * Opens a query object. 
       * This method is the equivalent of <code>QUERY-OPEN()</code> method from 4GL.
       * <u>Note</u>: You must perform <code>prepare()</code> on a query 
       * object before you perform <code>queryOpen</code> on it. 
       * 
       * @return  true on success
       */
      @Override
      public logical queryOpen()
      {
         return (logical.of(false));
      }

      /**
       * Conversion of INDEX-INFORMATION attribute (KW_IDX_INFO).
       *
       * Getter of INDEX-INFORMATION attribute.
       *
       * @return  Unknown value.
       */
      public character indexInformation()
      {
         return (new character());
      }

      /**
       * Conversion of INDEX-INFORMATION attribute (KW_IDX_INFO).
       *
       * Getter of INDEX-INFORMATION attribute
       *
       * @param n
       * An integer expression that evaluates to the level of join for which you want
       * index information.

       * @return  Unknown value.
       */
      public character indexInformation(int n)
      {
         return (new character());
      }

      /**
       * Conversion of INDEX-INFORMATION attribute (KW_IDX_INFO).
       *
       * Getter of INDEX-INFORMATION attribute
       *
       * @param    n
       *           An integer expression that evaluates to the level of join for which you want 
       *           index information.
       *           
       * @return   Unknown value.
       */
      public character indexInformation(NumberType n)
      {
         return (new character());
      }

      /**
       * Conversion of FORWARD-ONLY attribute (KW_FWD_ONLY).
       *
       * Getter of FORWARD-ONLY attribute.
       *
       * @return  <code>false</code>.
       */
      public logical forwardOnly()
      {
         return (logical.of(false));
      }

      /**
       * Conversion of FORWARD-ONLY attribute (KW_FWD_ONLY).
       *
       * Setter of FORWARD-ONLY attribute.
       *
       * @param  forwardOnly
       *         New value of FORWARD-ONLY attribute.
       */
      public void changeForwardOnly(logical forwardOnly)
      {
      }

      /**
       * Conversion of FORWARD-ONLY attribute (KW_FWD_ONLY).
       *
       * Setter of FORWARD-ONLY attribute.
       *
       * @param  forwardOnly
       *         New value of FORWARD-ONLY attribute.
       */
      public void changeForwardOnly(boolean forwardOnly)
      {
      }

      /**
       * Conversion of PREPARE_STRING attribute (KW_PREP_STR).
       *
       * Getter of PREPARE_STRING attribute.
       *
       * @return  Unknown value.
       */
      public character prepareString()
      {
         return (new character());
      }

      /**
       * Getter for the CACHE attribute.
       * 
       * @return   See above.
       */
      @Override
      public integer getCache()
      {
         return new integer();
      }
      
      /**
       * Setter for the CACHE attribute.
       * 
       * @param    n
       *           The cache value.
       */
      @Override
      public void setCache(integer n)
      {
      }
      
      /**
       * Setter for the CACHE attribute.
       * 
       * @param    n
       *           The cache value.
       */
      @Override
      public void setCache(long n)
      {
      }

      /**
       * Conversion of IS-OPEN attribute (KW_IS_OPEN).
       *
       * Getter of IS-OPEN attribute.
       *
       * @return current value of IS-OPEN attribute.
       */
      public logical isOpen()
      {
         return (logical.of(false));
      }

      /**
       * Conversion of GET-NEXT method (KW_GET_NEXT).
       *
       * Moves a query object's result list pointer ahead one row.
       *
       * @return  <code>false</code>.
       */
      @Override
      public boolean _getNext()
      {
         return false;
      }

      /**
       * Conversion of GET-NEXT method (KW_GET_NEXT).
       *
       * Moves a query object's result list pointer ahead one row.
       *
       * @param   lockType
       *          Lock type.
       *
       * @return  <code>false</code>.
       */
      public logical getNext(LockType lockType)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-NEXT method (KW_GET_NEXT).
       *
       * Moves a query object's result list pointer ahead one row.
       *
       * @param   lock
       *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
       *
       * @return  <code>false</code>.
       *
       * @throws  IllegalArgumentException
       *          if <code>lock</code> has not valid internal value.
       */
      public logical getNext(long lock)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-NEXT method (KW_GET_NEXT).
       *
       * Moves a query object's result list pointer ahead one row.
       *
       * @param   lock
       *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
       *
       * @return  <code>false</code>.
       *
       * @throws  IllegalArgumentException
       *          if <code>lock</code> has not valid internal value.
       */
      public logical getNext(NumberType lock)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-NEXT method (KW_GET_NEXT).
       *
       * Moves a query object's result list pointer ahead one row.
       *
       * @param   lock
       *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
       * @param   nowait
       *          NO-WAIT
       *
       * @return  <code>false</code>.
       *
       * @throws  IllegalArgumentException
       *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
       */
      public logical getNext(long lock, long nowait)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-NEXT method (KW_GET_NEXT).
       *
       * Moves a query object's result list pointer ahead one row.
       *
       * @param   lock
       *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
       * @param   nowait
       *          NO-WAIT
       *
       * @return  <code>false</code>.
       *
       * @throws  IllegalArgumentException
       *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
       */
      public logical getNext(long lock, NumberType nowait)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-NEXT method (KW_GET_NEXT).
       *
       * Moves a query object's result list pointer ahead one row.
       *
       * @param   lock
       *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
       * @param   nowait
       *          NO-WAIT
       *
       * @return  <code>false</code>.
       *
       * @throws  IllegalArgumentException
       *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
       */
      public logical getNext(NumberType lock, long nowait)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-NEXT method (KW_GET_NEXT).
       *
       * Moves a query object's result list pointer ahead one row.
       *
       * @param   lock
       *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
       * @param   nowait
       *          NO-WAIT
       *
       * @return  <code>false</code>.
       *
       * @throws  IllegalArgumentException
       *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
       */
      public logical getNext(NumberType lock, NumberType nowait)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-PREV method (KW_GET_PREV).
       *
       * Moves a query object's result list pointer back one row.
       *
       * @return  <code>false</code>.
       */
      public logical getPrevious()
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-PREV method (KW_GET_PREV).
       *
       * Moves a query object's result list pointer back one row.
       *
       * @param   lock
       *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
       *
       * @return  <code>false</code>.
       *
       * @throws  IllegalArgumentException
       *          if <code>lock</code> has not valid internal value.
       */
      public logical getPrevious(long lock)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-PREV method (KW_GET_PREV).
       *
       * Moves a query object's result list pointer back one row.
       *
       * @param   lockType
       *          Lock type.
       *
       * @return  <code>false</code>.
       *
       * @throws  IllegalArgumentException
       *          if <code>lock</code> has not valid internal value.
       */
      public logical getPrevious(LockType lockType)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-PREV method (KW_GET_PREV).
       *
       * Moves a query object's result list pointer back one row.
       *
       * @param   lock
       *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
       *
       * @return  <code>false</code>.
       *
       * @throws  IllegalArgumentException
       *          if <code>lock</code> has not valid internal value.
       */
      public logical getPrevious(NumberType lock)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-PREV method (KW_GET_PREV).
       *
       * Moves a query object's result list pointer back one row.
       *
       * @param   lock
       *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
       * @param   nowait
       *          NO-WAIT
       *
       * @return  <code>false</code>.
       *
       * @throws  IllegalArgumentException
       *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
       */
      public logical getPrevious(long lock, long nowait)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-PREV method (KW_GET_PREV).
       *
       * Moves a query object's result list pointer back one row.
       *
       * @param   lock
       *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
       * @param   nowait
       *          NO-WAIT
       *
       * @return  <code>false</code>.
       *
       * @throws  IllegalArgumentException
       *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
       */
      public logical getPrevious(NumberType lock, long nowait)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-PREV method (KW_GET_PREV).
       *
       * Moves a query object's result list pointer back one row.
       *
       * @param   lock
       *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
       * @param   nowait
       *          NO-WAIT
       *
       * @return  <code>false</code>.
       *
       * @throws  IllegalArgumentException
       *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
       */
      public logical getPrevious(long lock, NumberType nowait)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-PREV method (KW_GET_PREV).
       *
       * Moves a query object's result list pointer back one row.
       *
       * @param   lock
       *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
       * @param   nowait
       *          NO-WAIT
       *
       * @return  <code>false</code>.
       *
       * @throws  IllegalArgumentException
       *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
       */
      public logical getPrevious(NumberType lock, NumberType nowait)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-FIRST method (KW_GET_1ST).
       *
       * Moves a query object's result list pointer to the first row.
       *
       * @return  <code>false</code>.
       */
      public logical getFirst()
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-FIRST method (KW_GET_1ST).
       *
       * Moves a query object's result list pointer to the first row.
       *
       * @param   lock
       *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
       *
       * @return  <code>false</code>.
       *
       * @throws  IllegalArgumentException
       *          if <code>lock</code> has not valid internal value.
       */
      public logical getFirst(long lock)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-FIRST method (KW_GET_1ST).
       *
       * Moves a query object's result list pointer to the first row.
       *
       * @param   lock
       *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
       *
       * @return  <code>false</code>.
       *
       * @throws  IllegalArgumentException
       *          if <code>lock</code> has not valid internal value.
       */
      public logical getFirst(NumberType lock)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-FIRST method (KW_GET_1ST).
       *
       * Moves a query object's result list pointer to the first row.
       *
       * @param   lockType
       *          Lock type.
       *
       * @return  <code>false</code>.
       *
       * @throws  IllegalArgumentException
       *          if <code>lock</code> has not valid internal value.
       */
      public logical getFirst(LockType lockType)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-FIRST method (KW_GET_1ST).
       *
       * Moves a query object's result list pointer to the first row.
       *
       * @param   lock
       *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
       * @param   nowait
       *          NO-WAIT
       *
       * @return  <code>false</code>.
       *
       * @throws  IllegalArgumentException
       *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
       */
      public logical getFirst(long lock, long nowait)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-FIRST method (KW_GET_1ST).
       *
       * Moves a query object's result list pointer to the first row.
       *
       * @param   lock
       *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
       * @param   nowait
       *          NO-WAIT
       *
       * @return  <code>false</code>.
       *
       * @throws  IllegalArgumentException
       *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
       */
      public logical getFirst(NumberType lock, long nowait)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-FIRST method (KW_GET_1ST).
       *
       * Moves a query object's result list pointer to the first row.
       *
       * @param   lock
       *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
       * @param   nowait
       *          NO-WAIT
       *
       * @return  <code>false</code>.
       *
       * @throws  IllegalArgumentException
       *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
       */
      public logical getFirst(long lock, NumberType nowait)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-FIRST method (KW_GET_1ST).
       *
       * Moves a query object's result list pointer to the first row.
       *
       * @param   lock
       *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
       * @param   nowait
       *          NO-WAIT
       *
       * @return  <code>false</code>.
       *
       * @throws  IllegalArgumentException
       *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
       */
      public logical getFirst(NumberType lock, NumberType nowait)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-LAST method (KW_GET_LAST).
       *
       * Moves a query object's result list pointer to the last row.
       *
       * @return  <code>false</code>.
       */
      public logical getLast()
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-LAST method (KW_GET_LAST).
       *
       * Moves a query object's result list pointer to the last row.
       *
       * @param   lock
       *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
       *
       * @return  <code>false</code>.
       *
       * @throws  IllegalArgumentException
       *          if <code>lock</code> has not valid internal value.
       */
      public logical getLast(long lock)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-LAST method (KW_GET_LAST).
       *
       * Moves a query object's result list pointer to the last row.
       *
       * @param   lock
       *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
       *
       * @return  <code>false</code>.
       *
       * @throws  IllegalArgumentException
       *          if <code>lock</code> has not valid internal value.
       */
      public logical getLast(NumberType lock)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-LAST method (KW_GET_LAST).
       *
       * Moves a query object's result list pointer to the last row.
       *
       * @param   lockType
       *          Lock type.
       *
       * @return  <code>false</code>.
       *
       * @throws  IllegalArgumentException
       *          if <code>lock</code> has not valid internal value.
       */
      public logical getLast(LockType lockType)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-LAST method (KW_GET_LAST).
       *
       * Moves a query object's result list pointer to the last row.
       *
       * @param   lock
       *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
       * @param   nowait
       *          NO-WAIT
       *
       * @return  <code>false</code>.
       *
       * @throws  IllegalArgumentException
       *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
       */
      public logical getLast(long lock, long nowait)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-LAST method (KW_GET_LAST).
       *
       * Moves a query object's result list pointer to the last row.
       *
       * @param   lock
       *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
       * @param   nowait
       *          NO-WAIT
       *
       * @return  <code>false</code>.
       *
       * @throws  IllegalArgumentException
       *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
       */
      public logical getLast(NumberType lock, long nowait)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-LAST method (KW_GET_LAST).
       *
       * Moves a query object's result list pointer to the last row.
       *
       * @param   lock
       *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
       * @param   nowait
       *          NO-WAIT
       *
       * @return  <code>false</code>.
       *
       * @throws  IllegalArgumentException
       *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
       */
      public logical getLast(long lock, NumberType nowait)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-LAST method (KW_GET_LAST).
       *
       * Moves a query object's result list pointer to the last row.
       *
       * @param   lock
       *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
       * @param   nowait
       *          NO-WAIT
       *
       * @return  <code>false</code>.
       *
       * @throws  IllegalArgumentException
       *          if <code>lock</code> or <code>nowait</code> have not valid internal values.
       */
      public logical getLast(NumberType lock, NumberType nowait)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-CURRENT() method (KW_GET_CUR).
       *
       * Refetches the current record or records associated with the query.
       *
       * @return  <code>false</code>.
       */
      public logical getCurrent()
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-CURRENT() method (KW_GET_CUR).
       *
       * Refetches the current record or records associated with the query.
       *
       * @param   lock
       *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
       *
       * @return  <code>false</code>.
       */
      public logical getCurrent(long lock)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-CURRENT() method (KW_GET_CUR).
       *
       * Refetches the current record or records associated with the query.
       *
       * @param   lock
       *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
       *
       * @return  <code>false</code>.
       */
      public logical getCurrent(NumberType lock)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-CURRENT() method (KW_GET_CUR).
       *
       * Refetches the current record or records associated with the query.
       *
       * @param   lockType
       *          Lock type.
       *
       * @return  <code>false</code>.
       */
      public logical getCurrent(LockType lockType)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-CURRENT() method (KW_GET_CUR).
       *
       * Refetches the current record or records associated with the query.
       *
       * @param   lock
       *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
       * @param   nowait
       *          NO-WAIT
       *
       * @return  <code>false</code>.
       */
      public logical getCurrent(long lock, long nowait)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-CURRENT() method (KW_GET_CUR).
       *
       * Refetches the current record or records associated with the query.
       *
       * @param   lock
       *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
       * @param   nowait
       *          NO-WAIT
       *
       * @return  <code>false</code>.
       */
      public logical getCurrent(NumberType lock, long nowait)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-CURRENT() method (KW_GET_CUR).
       *
       * Refetches the current record or records associated with the query.
       *
       * @param   lock
       *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
       * @param   nowait
       *          NO-WAIT
       *
       * @return  <code>false</code>.
       */
      public logical getCurrent(long lock, NumberType nowait)
      {
         return logical.of(false);
      }

      /**
       * Conversion of GET-CURRENT() method (KW_GET_CUR).
       *
       * Refetches the current record or records associated with the query.
       *
       * @param   lock
       *          SHARE-LOCK|EXCLUSIVE-LOCK|NO-LOCK
       * @param   nowait
       *          NO-WAIT
       *
       * @return  <code>false</code>.
       */
      public logical getCurrent(NumberType lock, NumberType nowait)
      {
         return logical.of(false);
      }

      /**
       * Conversion of NUM-BUFFERS() method (KW_NUM_BUFF).
       *
       * @return  the number of buffers in a query or DataSet object.
       */
      public integer numBuffers()
      {
         return new integer();
      }
      
      /**
       * Setter for SKIP-DELETED-RECORD query attribute. 
       *
       * @param   on
       *          New value for the attribute.
       */
      @Override
      public void setSkipDeletedRecord(logical on)
      {
         // no-op
      }
      
      /**
       * Get value of SKIP-DELETED-RECORD attribute of the query.
       *
       * @return  the value of SKIP-DELETED-RECORD attribute of the query.
       */
      @Override
      public logical isSkipDeletedRecord()
      {
         return logical.of(true); // default value
      }
      
      /**
       * No-op.
       *
       * @param dmo
       *        Not used.
       * @param fields
       *        Not used.
       */
      public void include(DataModelObject dmo, String ... fields)
      {
      }

      /**
       * No-op.
       *
       * @param dmo
       *        Not used.
       * @param fields
       *        Not used.
       */
      public void exclude(DataModelObject dmo, String ... fields)
      {
      }

      /**
       * No-op.
       *
       * @return <code>false</code>.
       */
      public logical deleteResultListEntry()
      {
         return logical.of(false);
      }
      
      /**
       * No-op.
       *
       * @return <code>false</code>.
       */
      public logical deleteResultListEntry(boolean allowBetweenRows)
      {
         return logical.of(false);
      }
      
      /**
       * No-op.
       *
       * @return <code>false</code>.
       */
      @Override
      public logical createResultListEntry()
      {
         return logical.of(false);
      }
      
      /**
       * No-op.
       *
       * @param   parameterFilter
       *          Not used.
       */
      @Override
      public void setParameterFilter(ParameterFilter parameterFilter)
      {
      }
      
      /**
       * No-op.
       */
      @Override
      public void releaseBuffers()
      {
      }
      
      /**
       * Adds a new constraint term to the where predicate of this query, effectively filtering out
       * any rows whose referenced field does not match the requested value. Semantically, the
       * query will select rows that match
       * <p>
       * {@code new-where := (fr = val) AND (old-query)}.
       * <p>
       * Note: The constraints are exclusive meaning that if constraints will be added for same
       * field of same buffer, the query will return an empty result because the field cannot be
       * at the same time equals to two different values.
       * <p>
       * Use {@link #clearDynamicFilters} to clean all dynamically added criteria and restore the
       * sorting order of the query to its original form.
       *
       * @param   fr
       *          A reference to field used as filtering criterion. Only the rows that matches the
       *          specified value for this field will be selected. Must not be {@code null}. 
       * @param   val
       *          The filtering value for this constraint. Can be {@code null} or {@code unknown},
       *          in which case the SQL {@code null} value will be assumed. In this case the
       *          predicate will look like:
       *           <p>
       *          {@code new-where := (fr IS  NULL) AND (old-query)}
       * @param   format
       *          The format to be used when comparing values. The reason for this parameter is that
       *          for some datatype (ex: {@code decimal}) the on-screen value can be different from
       *          the database (because of rounding).
       *
       * @return  {@code true} if the filtering constraint was successfully added. If the field
       *          reference is not related to the buffer(s) of this query, {@code false} is
       *          returned.
       */
      @Override
      public boolean addDynamicFilter(FieldReference fr, BaseDataType val, String format)
      {
         return false;
      }
      
      /**
       * Clears any dynamically filters added at runtime. The query predicate will be restored to
       * its form from generated at conversion time. 
       */
      @Override
      public void clearDynamicFilters()
      {
         //no-op
      }

      @Override
      public void setLenientOffEnd(boolean lenientOffEnd)
      {
         //no-op
      }
      
      /**
       * Indicate whether the query is defined inside the scope of FOR EACH block.
       *
       * @param   iterating
       *          <code>true</code> indicating that a query is inside FOR EACH block;
       *          <code>false</code> is defined outside of a FOR EACH.
       */
      @Override
      public void setIterating(boolean iterating) 
      {
         //no-op
      }
      
      /**
       * Indicate whether the query is defined inside the scope of FOR EACH block.
       *
       * @return  <code>true</code> if the query was defined inside a FOR EACH block.
       */
      @Override
      public boolean isIterating() 
      {
         return false;
      }
      
      /**
       * Indicate whether the delegate query is of presort type.
       *
       * @return  <code>true</code> if the query is of presort type.
       */
      @Override
      public boolean isPresort() 
      {
         return false;
      }
      
      /**
       * Indicate whether the delegate query is of presort type.
       *
       * @param   presort
       *          <code>true</code> indicating that a query of presort type.
       *          <code>false</code> is not of presort type.
       */
      @Override
      public void setPresort(boolean presort) 
      {
         //no-op
      }
   }
}