# 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
          }
       }
    }